本篇為用go設計開發一個自己的輕量級登入庫/框架吧 - 秋玻 - 部落格園 (cnblogs.com)的封禁業務篇,會講講封禁業務的實現,給庫/框架增加新的功能。
原始碼:https://github.com/weloe/token-go
封禁業務也是在一般專案中比較常見的業務。我們也將它封裝在庫中作為功能之一。
我們同樣使用adapter作為底層的儲存結構,將封禁標示作為k-v結構儲存。
把id和服務名稱service作為key,把封禁的級別level作為value,以此我們能實現一些比較常見的封禁業務。
首先就是封禁方法,首先當然要校驗一下引數,然後儲存封禁標識。要注意的就是level要大於等於1,在封禁後也要呼叫我們的logger和watcher。
https://github.com/weloe/token-go/blob/8bf577c0309332cb42d17e33b435f06fb74d8e7b/enforcer.go#L390
// Banned ban user, if time == 0,the timeout is not set
func (e *Enforcer) Banned(id string, service string, level int, time int64) error {
if id == "" || service == "" {
return fmt.Errorf("parameter cannot be nil")
}
if level < 1 {
return fmt.Errorf("unexpected level = %v, level must large or equal 1", level)
}
err := e.adapter.SetStr(e.spliceBannedKey(id, service), strconv.Itoa(level), time)
if err != nil {
return err
}
// callback
e.logger.Ban(e.loginType, id, service, level, time)
if e.watcher != nil {
e.watcher.Ban(e.loginType, id, service, level, time)
}
return nil
}
再來就是解除封禁的實現,很簡單,只要刪除我們封禁存的那條記錄就可以了。
// UnBanned Unblock user account
func (e *Enforcer) UnBanned(id string, services ...string) error {
if id == "" {
return fmt.Errorf("parmeter id can not be nil")
}
if len(services) == 0 {
return fmt.Errorf("parmeter services length can not be 0")
}
for _, service := range services {
err := e.adapter.DeleteStr(e.spliceBannedKey(id, service))
if err != nil {
return err
}
e.logger.UnBan(e.loginType, id, service)
if e.watcher != nil {
e.watcher.UnBan(e.loginType, id, service)
}
}
return nil
}
接著還需要提供幾個方便使用的方法
分別用來判斷是否被封禁,獲得封禁的級別,獲得封禁的剩餘時間三個方法
https://github.com/weloe/token-go/blob/8bf577c0309332cb42d17e33b435f06fb74d8e7b/enforcer.go#L434
判斷是否被封禁
// IsBanned if banned return true, else return false
func (e *Enforcer) IsBanned(id string, services string) bool {
s := e.adapter.GetStr(e.spliceBannedKey(id, services))
return s != ""
}
https://github.com/weloe/token-go/blob/8bf577c0309332cb42d17e33b435f06fb74d8e7b/enforcer.go#L441
獲得封禁的級別
// GetBannedLevel get banned level
func (e *Enforcer) GetBannedLevel(id string, service string) (int64, error) {
str := e.adapter.GetStr(e.spliceBannedKey(id, service))
if str == "" {
return 0, fmt.Errorf("loginId = %v, service = %v is not banned", id, service)
}
time, err := strconv.ParseInt(str, 10, 64)
if err != nil {
return 0, err
}
return time, nil
}
https://github.com/weloe/token-go/blob/8bf577c0309332cb42d17e33b435f06fb74d8e7b/enforcer.go#L454
獲得封禁的剩餘時間
// GetBannedTime get banned time
func (e *Enforcer) GetBannedTime(id string, service string) int64 {
timeout := e.adapter.GetStrTimeout(e.spliceBannedKey(id, service))
return timeout
}
有了這幾個方法,我們就可以使用token-go更為方便是實現登入業務了。
對於一般的業務,我們其實可以無視封禁級別。只需要使用Banned()
進行封禁,在每個需要校驗是否被封禁的業務前進行IsBanned()
的判斷就行了。
測試例子:
func TestEnforcer_Banned(t *testing.T) {
err, enforcer, _ := NewTestEnforcer(t)
if err != nil {
t.Fatalf("NewTestEnforcer() failed: %v", err)
}
err = enforcer.Banned("1", "comment", 1, 100)
if err != nil {
t.Fatalf("Banned() failed: %v", err)
}
isBanned := enforcer.IsBanned("1", "comment")
if !isBanned {
t.Errorf("unexpected isBanned is false")
}
err = enforcer.UnBanned("1", "comment")
if err != nil {
t.Fatalf("UnBanned() failed: %v", err)
}
isBanned = enforcer.IsBanned("1", "comment")
if isBanned {
t.Errorf("unexpected isBanned is false")
}
}
當然我們對於一個業務會有一些較為複雜的封禁,比如discuss
交流業務,如果級別為1我們會禁止評論,如果級別為2我們會禁止評論和點贊,級別為3我們會禁止評論、點贊和收藏。
這個時候我們只需要再加上GetBannedLevel()
,在每個業務前獲取封禁級別進行判斷就可以簡單的實現了。