用go設計開發一個自己的輕量級登錄庫/框架吧 幾乎每個項目都會有登錄,退出等用戶功能,而登錄又不單僅僅是登錄,我們要考慮很多東西。 token該怎麼生成?生成什麼樣的? 是在Cookie存token還是請求頭存token?讀取的時候怎麼讀取? 允許同一個賬號被多次登錄嗎?多次登錄他們的token是一 ...
用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
var _ IEnforcer = &Enforcer{}
type IEnforcer interface {
Login(id string) (string, error)
LoginByModel(id string, loginModel *model.Login) (string, error)
Logout() error
IsLogin() (bool, error)
IsLoginById(id string) (bool, error)
GetLoginId() (string, error)
Replaced(id string, device string) error
Kickout(id string, device string) error
GetRequestToken() string
SetType(t string)
GetType() string
SetContext(ctx ctx.Context)
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
}
到此,項目的大致的結構就設計完成,下一篇會講講本業務的具體實現