用go設計開發一個自己的輕量級登入庫/框架吧

秋玻發表於2023-05-06

用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
}

到此,專案的大致的結構就設計完成,下一篇會講講本業務的具體實現

相關文章