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

139 阅读3分钟

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

几乎每个项目都会有登录,退出等用户功能,而登录又不单仅仅是登录,我们要考虑很多东西。

token该怎么生成?生成什么样的?

是在Cookie存token还是请求头存token?读取的时候怎么读取?

允许同一个账号被多次登录吗?多次登录他们的token是一样的?还是不一样的?

登录也有可能分成管理员登录,用户登录等多种登录类型

我们要做的就是把这些东西封装到一起,然后能更方便的使用

而完成这些最难的就是如何设计架构了,其实要简单的封装一下并不难,本篇要讲的就是如何进行架构的设计了。

源码:weloe/token-go: a light login library (github.com)

Enforcer

我们可以抽象出一个供外部调用的执行器,它包括以下几个部分

token-go/enforcer.go at master · weloe/token-go (github.com)

type Enforcer struct {
    // 从配置文件读取配置需要
    conf         string
    // 登录类型
    loginType    string
    config       config.TokenConfig
    // 生成token的函数
    generateFunc model.GenerateTokenFunc
    // 用于存储数据
    adapter      persist.Adapter
    // 监听器
    watcher      persist.Watcher
    // 用于记录日志
    logger       log.Logger
}

执行器的接口,包含供外部调用的方法

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

type IEnforcer interface {
    Login(id string, ctx ctx.Context) (string, error)
    LoginByModel(id string, loginModel *model.Login, ctx ctx.Context) (string, error)
    Logout(ctx ctx.Context) error
    IsLogin(ctx ctx.Context) (bool, error)
    IsLoginById(id string) (bool, error)
    GetLoginId(ctx ctx.Context) (string, error)
​
    Replaced(id string, device string) error
    Kickout(id string, device string) error
​
    GetRequestToken(ctx ctx.Context) string
​
    SetType(t string)
    GetType() string
    GetAdapter() persist.Adapter
    SetAdapter(adapter persist.Adapter)
    SetWatcher(watcher persist.Watcher)
    SetLogger(logger log.Logger)
    EnableLog()
    IsLogEnable() bool
    GetSession(id string) *model.Session
    SetSession(id string, session *model.Session, timeout int64) error
}
​

Config

首先就是根据需求抽象出配置信息

一个是cookie的配置

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

type CookieConfig struct {
    Domain   string
    Path     string
    Secure   bool
    HttpOnly bool
    SameSite string
}

一个是token的配置

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

type TokenConfig struct {
   // TokenStyle
   // uuid | uuid-simple | random-string32 | random-string64 | random-string128
   TokenStyle string
    
   TokenName   string
​
   Timeout int64
​
   // 允许多次登录
   IsConcurrent bool
   // 多次登录共享一个token
   IsShare bool
   // If (IsConcurrent == true && IsShare == false)才支持配置
   // If IsConcurrent == -1, 不检查登录数量
   MaxLoginCount int16
​
   // 读取token的方式
   IsReadBody   bool
   IsReadHeader bool
   IsReadCookie bool
​
   // 是否把token写入响应头
   IsWriteHeader bool
​
   CookieConfig *CookieConfig
}

Adapter

adapter是底层用来存储数据的结构,为了兼容不同的实现(不同的存储方式),设计成一个接口。

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

type Adapter interface {
​
    // GetStr string operate string value
    GetStr(key string) string
    // SetStr set store value and timeout
    SetStr(key string, value string, timeout int64) error
    // UpdateStr only update value
    UpdateStr(key string, value string) error
    // DeleteStr delete string value
    DeleteStr(key string) error
    // GetStrTimeout get expire
    GetStrTimeout(key string) int64
    // UpdateStrTimeout update expire time
    UpdateStrTimeout(key string, timeout int64) error
​
    // Get get interface{}
    Get(key string) interface{}
    // Set store interface{}
    Set(key string, value interface{}, timeout int64) error
    // Update only update interface{} value
    Update(key string, value interface{}) error
    // Delete delete interface{} value
    Delete(key string) error
    // GetTimeout get expire
    GetTimeout(key string) int64
    // UpdateTimeout update timeout
    UpdateTimeout(key string, timeout int64) error
}
​

Context

我们需要从请求读取token,可能也需要写出token,因此需要兼容不同的web上下文,我们需要设计一个Context接口

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

type Context interface {
    Request() Request
    Response() Response
    ReqStorage() ReqStorage
    MatchPath(pattern string, path string) bool
    IsValidContext() bool
}

Watcher

监听器,用于在一些事件发生的时候进行一些其他操作。

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

// Watcher event watcher
type Watcher interface {
    // Login called after login
    Login(loginType string, id interface{}, tokenValue string, loginModel *model.Login)
    // Logout called after logout
    Logout(loginType string, id interface{}, tokenValue string)
}

Logger

Logger,用于记录日志,方便debug等等,需要设计成可以自由开启关闭。

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

type Logger interface {
    persist.Watcher
​
    // Enable turn on or off
    Enable(bool bool)
​
    // IsEnabled return if logger is enabled
    IsEnabled() bool
}

到此,项目的大致的结构就设计完成,下一篇会讲讲本业务的具体实现