用go设计开发一个自己的轻量级登录库/框架吧(拓展篇)

这篇具有很好参考价值的文章主要介绍了用go设计开发一个自己的轻量级登录库/框架吧(拓展篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

给自己的库/框架拓展一下吧(拓展篇)

主库:weloe/token-go: a light login library.

扩展库:weloe/token-go-extensions (github.com)

本篇给主库扩展一个Adapter提供简单的外部数据存储。

思路

一个库/框架往往不能完成所有事情,需要其他库/框架的支持才能达到更加完善的效果。本篇会对token-go框架的Adapter进行简单的拓展。

首先我们应该想想Adapter是用来干什么的?

从第一篇我们就明确其职责,就是存储数据。我们在token-go里提供了一个内置的adapter:default_adapter,用于框架底层的数据存储,但是这种内存的数据存储有着很多的缺陷,并且没有经过实际的生产测试使用。也因此,我们应该提供更成熟的存储方案来提供给使用者去替代它。

这就是本篇要实现的redis_adapter了

实现

这里还有一个点要注意,将数据存储到外部需要确定数据的序列化和反序列化方法。因此,我们加了一个SerializerAdapter接口,要求新的Adapter选择实现。

token-go/serializer_adapter.go at master · weloe/token-go · GitHub

package persist

import "github.com/weloe/token-go/model"

type SerializerAdapter interface {
	Adapter
	Serialize(*model.Session) ([]byte, error)
	UnSerialize([]byte) (*model.Session, error)
}

具体的调用则是在enforcer对session进行存储或者取出数据的时候进行调用。

func (e *Enforcer) GetSession(id string) *model.Session {
	if v := e.adapter.Get(e.spliceSessionKey(id)); v != nil {
		if s := e.sessionUnSerialize(v); s != nil {
			return s
		} else {
			session, ok := v.(*model.Session)
			if !ok {
				return nil
			}
			return session
		}
	}
	return nil
}

这里的sessionUnSerialize()实际上就是尝试调用了adapter实现的反序列化方法。同理SetSession()也是一样的。

最后就是RedisAdapter了

token-go-extensions/adapter.go at master · weloe/token-go-extensions · GitHub

并不难,只要实现我们之前的Adapter和SerializerAdapter两个接口就行了。

序列化方法使用json,方便查看

package redis_adapter

import (
	"context"
	"encoding/json"
	"github.com/go-redis/redis/v8"
	"github.com/weloe/token-go/model"
	"github.com/weloe/token-go/persist"
	"time"
)

var _ persist.Adapter = (*RedisAdapter)(nil)

var _ persist.SerializerAdapter = (*RedisAdapter)(nil)

type RedisAdapter struct {
	client *redis.Client
}

func (r *RedisAdapter) Serialize(session *model.Session) ([]byte, error) {
	return json.Marshal(session)
}

func (r *RedisAdapter) UnSerialize(bytes []byte) (*model.Session, error) {
	s := &model.Session{}
	err := json.Unmarshal(bytes, s)
	if err != nil {
		return nil, err
	}
	return s, nil
}

func (r *RedisAdapter) GetStr(key string) string {
	res, err := r.client.Get(context.Background(), key).Result()
	if err != nil {
		return ""
	}
	return res
}

func (r *RedisAdapter) SetStr(key string, value string, timeout int64) error {
	err := r.client.Set(context.Background(), key, value, time.Duration(timeout)*time.Second).Err()
	if err != nil {
		return err
	}
	return nil
}

func (r *RedisAdapter) UpdateStr(key string, value string) error {
	err := r.client.Set(context.Background(), key, value, 0).Err()
	if err != nil {
		return err
	}
	return nil
}

func (r *RedisAdapter) DeleteStr(key string) error {
	err := r.client.Del(context.Background(), key).Err()
	if err != nil {
		return err
	}
	return nil
}

func (r *RedisAdapter) GetStrTimeout(key string) int64 {
	duration, err := r.client.TTL(context.Background(), key).Result()
	if err != nil {
		return -1
	}
	return int64(duration.Seconds())
}

func (r *RedisAdapter) UpdateStrTimeout(key string, timeout int64) error {
	var duration time.Duration
	if timeout < 0 {
		duration = -1
	} else {
		duration = time.Duration(timeout) * time.Second
	}
	err := r.client.Expire(context.Background(), key, duration).Err()
	if err != nil {
		return err
	}
	return nil
}

func (r *RedisAdapter) Get(key string) interface{} {
	res, err := r.client.Get(context.Background(), key).Result()
	if err != nil {
		return nil
	}
	s := &model.Session{}
	err = json.Unmarshal([]byte(res), s)
	if err != nil {
		return nil
	}
	return s
}

func (r *RedisAdapter) Set(key string, value interface{}, timeout int64) error {
	err := r.client.Set(context.Background(), key, value, time.Duration(timeout)*time.Second).Err()
	if err != nil {
		return err
	}
	return nil
}

func (r *RedisAdapter) Update(key string, value interface{}) error {
	err := r.client.Set(context.Background(), key, value, 0).Err()
	if err != nil {
		return err
	}
	return nil
}

func (r *RedisAdapter) Delete(key string) error {
	err := r.client.Del(context.Background(), key).Err()
	if err != nil {
		return err
	}
	return nil
}

func (r *RedisAdapter) GetTimeout(key string) int64 {
	duration, err := r.client.TTL(context.Background(), key).Result()
	if err != nil {
		return -1
	}
	return int64(duration.Seconds())
}

func (r *RedisAdapter) UpdateTimeout(key string, timeout int64) error {
	var duration time.Duration
	if timeout < 0 {
		duration = -1
	} else {
		duration = time.Duration(timeout) * time.Second
	}
	err := r.client.Expire(context.Background(), key, duration).Err()
	if err != nil {
		return err
	}
	return nil
}

func (r *RedisAdapter) DeleteBatchFilteredKey(filterKeyPrefix string) error {
	var cursor uint64 = 0
	for {
		keys, cursor, err := r.client.Scan(context.Background(), cursor, filterKeyPrefix+"*", 100).Result()
		if err != nil {
			return err
		}

		if len(keys) == 0 && cursor == 0 {
			break
		}

		// use pip delete batch
		pipe := r.client.Pipeline()

		for _, key := range keys {
			pipe.Del(context.Background(), key)
		}

		_, err = pipe.Exec(context.Background())
		if err != nil {
			return err
		}
	}

	return nil
}

实现完接口,再写几个初始化方法

func NewAdapter(addr string, username string, password string, db int) (*RedisAdapter, error) {
	return NewAdapterByOptions(&redis.Options{
		Addr:     addr,
		Username: username,
		Password: password,
		DB:       db,
	})
}

func NewAdapterByOptions(options *redis.Options) (*RedisAdapter, error) {
	client := redis.NewClient(options)
	_, err := client.Ping(context.Background()).Result()
	if err != nil {
		return nil, err
	}
	return &RedisAdapter{client: client}, nil
}

测试

就不贴测试代码了,就放个链接~

token-go-extensions/adapter_test.go at master · weloe/token-go-extensions · GitHub

最后

这样RedisAdapter就开发完了吗?不不不,并没有。

用户量的增大,对容错,一致性等等的要求提高,可能需要用到多个redis,这就需要我们继续适配开发一个ClusterAdapter了,为什么我这里不往下写了?阳了好累当然是因为还在开发中~~文章来源地址https://www.toymoban.com/news/detail-453361.html

到了这里,关于用go设计开发一个自己的轻量级登录库/框架吧(拓展篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • go-carbon 2.2.12 版本发布, 轻量级、语义化、对开发者友好的 Golang 时间处理库

    carbon 是一个轻量级、语义化、对开发者友好的 golang 时间处理库,支持链式调用。 目前已被 awesome-go 收录,如果您觉得不错,请给个 star 吧 github.com/golang-module/carbon gitee.com/golang-module/carbon 安装使用 Golang 版本大于等于1.16 Golang 版本小于1.16 更新日志 增加对荷兰语的支持 测试

    2024年02月06日
    浏览(36)
  • go-carbon v2.3.5 发布,轻量级、语义化、对开发者友好的 golang 时间处理库

    carbon 是一个轻量级、语义化、对开发者友好的 golang 时间处理库,支持链式调用。 目前已被 awesome-go 收录,如果您觉得不错,请给个 star 吧 github.com/golang-module/carbon gitee.com/golang-module/carbon 安装使用 Golang 版本大于等于 1.16 Golang 版本小于 1.16 更新日志 Default 结构体新增 Locale

    2024年02月01日
    浏览(38)
  • 使用Go语言打造轻量级Web框架

    前言 Web框架是Web开发中不可或缺的组件。它们的主要目标是抽象出HTTP请求和响应的细节,使开发人员可以更专注于业务逻辑的实现。在本篇文章中,我们将使用Go语言实现一个简单的Web框架,类似于Gin框架。 功能 我们的Web框架需要实现以下功能: 路由:处理HTTP请求的路由

    2023年04月08日
    浏览(33)
  • 特制自己的ChatGPT:多接口统一的轻量级LLM-IFT平台

    ©PaperWeekly 原创 · 作者 |  佀庆一 单位 |  中科院信息工程研究所 研究方向 |  视觉问答 项目简称: Alpaca-CoT(当羊驼遇上思维链) 项目标题: Alpaca-CoT: An Instruction Fine-Tuning Platform with Instruction Data Collection and Unified Large Language Models Interface 项目链接: https://github.com/PhoebusSi

    2024年02月04日
    浏览(26)
  • C#轻量级日志功能(只有一个类)

    最近在开发基于.net6的一个数据监控软件,使用其它开源log库都有点麻烦,就想着对Console.WriteLine()方法重定向到文件,非常方便的实现日志记录功能,同时也不影响之前的代码结构。 软件开始的地方要设置该重定向:

    2024年01月21日
    浏览(47)
  • CasaOS一个轻量级的家庭云系统

    简介 CasaOS是一款轻量级的家庭云系统,基于Docker安装部署,支持pc和手机,可玩性非常高,万物皆可以打成docker镜像后都可以安装。 你要你拥有一台电脑装上ubuntu你就能做all in one ,nas全家桶。安装简单,但是受网速影响至少要一个小时。 准备工作 一台装有docker的ubantu系统

    2024年02月05日
    浏览(38)
  • 轻量灵动: 革新轻量级服务开发

    从 JDK 8 升级到 JDK 17 可以让你的应用程序受益于新的功能、性能改进和安全增强。下面是一些 JDK 8 升级到 JDK 17 的最佳实战: 1.1、确定升级的必要性:首先,你需要评估你的应用程序是否需要升级到 JDK 17。查看 JDK 17 的新特性、改进和修复的 bug,以确定它们对你的应用程序

    2024年02月07日
    浏览(35)
  • Mainflux IoT:Go语言轻量级开源物联网平台,支持HTTP、MQTT、WebSocket、CoAP协议

    Mainflux是一个由法国的创业公司开发并维护的 安全、可扩展 的开源物联网平台,使用 Go语言开发、采用微服务的框架。Mainflux支持多种接入设备,包括设备、用户、APP;支持多种协议,包括HTTP、MQTT、WebSocket、CoAP,并支持他们之间的协议互转。 Mainflux的南向接口连接设备,北

    2024年02月01日
    浏览(95)
  • 【KRouter】一个简单且轻量级的Kotlin Routing框架

    KRouter(Kotlin-Router)是一个简单而轻量级的Kotlin路由框架。 具体来说,KRouter是一个通过URI来发现接口实现类的框架。它的使用方式如下: 之所以这样做,是因为在使用Voyager一段时间后,我发现模块之间的通信不够灵活,需要一些配置,而且使用DeepLink有点奇怪,所以我更喜

    2024年02月09日
    浏览(27)
  • 教你使用PHP实现一个轻量级HTML模板引擎

    🏆作者简介,黑夜开发者,全栈领域新星创作者✌,2023年6月csdn上海赛道top4。多年电商行业从业经验,对系统架构,数据分析处理等大规模应用场景有丰富经验。 🏆本文已收录于PHP专栏:PHP进阶实战教程。 🏆另有专栏PHP入门基础教程,希望各位大佬多多支持❤️。 在 W

    2024年02月15日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包