用go封裝一下臨時token

2023-10-28 18:00:23

用go封裝一下臨時token

本篇為用go設計開發一個自己的輕量級登入庫/框架吧 的臨時token篇,會講講臨時token的實現,給庫/框架增加新的功能。

Github:https://github.com/weloe/token-go

臨時token也算是比較常見的業務,例如登入驗證碼資訊,邀請連結等等,都屬於臨時token的範疇。

在token-go中同樣使用Adapter元件進行了簡單的封裝。

封裝思路

對於一個登入驗證碼,我們需要有建立,有效期,需要解析,需要能刪除的功能。

因此,我們需要建立臨時token,獲取臨時token有效期,解析臨時token,刪除臨時token這幾個方法。

而臨時token會跟業務資訊做關聯,比如這個臨時token是用於驗證碼服務或是用於邀請服務他們是互相隔離的,因此在儲存的時候我們需要一個service引數做區分,我們儲存為k,v結構,儲存的key結構為: "token-go:" + "temp-token" + ":temp:" + service + ":" + token,儲存的value即為設定的對應的值。

最後決定出幾個api

	// Temp token api
	CreateTempToken(token string, service string, value string, timeout int64) (string, error)
	CreateTempTokenByStyle(style string, service string, value string, timeout int64) (string, error)
	GetTempTokenTimeout(service string, tempToken string) int64
	ParseTempToken(service string, tempToken string) string
	DeleteTempToken(service string, tempToken string) error

程式碼實現

建立臨時token

這裡我們提供了兩個方法,一個用於根據style使用內建建立token的函數建立token,另一個用於直接由開發者生成token再傳入。建立token則是Adapter對資訊進行儲存。

通過指定style建立

https://github.com/weloe/token-go/blob/90e576f01537c92b924670dee3e32b8d7f010585/enforcer_manager_api.go#L211

func (e *Enforcer) CreateTempTokenByStyle(style string, service string, value string, timeout int64) (string, error) {
	token, err := e.generateFunc.Exec(style)
	if err != nil {
		return "", err
	}
	err = e.setTempToken(service, token, value, timeout)
	if err != nil {
		return "", err
	}
	return token, nil
}

指定token建立。

https://github.com/weloe/token-go/blob/90e576f01537c92b924670dee3e32b8d7f010585/enforcer_manager_api.go#L223

func (e *Enforcer) CreateTempToken(token string, service string, value string, timeout int64) (string, error) {
	if token == "" {
		return "", fmt.Errorf("token must not be empty")
	}
	err := e.setTempToken(service, token, value, timeout)
	if err != nil {
		return "", err
	}
	return token, nil
}

獲取剩餘時間

https://github.com/weloe/token-go/blob/90e576f01537c92b924670dee3e32b8d7f010585/enforcer_manager_api.go#L234

同樣是使用Adapter元件去獲取剩餘時間

func (e *Enforcer) GetTempTokenTimeout(service string, tempToken string) int64 {
	if tempToken == "" {
		return constant.NotValueExpire
	}
	return e.getTimeoutByTempToken(service, tempToken)
}
func (e *Enforcer) getTimeoutByTempToken(service string, token string) int64 {
	return e.adapter.GetTimeout(e.spliceTempTokenKey(service, token))
}

解析臨時token

https://github.com/weloe/token-go/blob/90e576f01537c92b924670dee3e32b8d7f010585/enforcer_manager_api.go#L241

解析即是通過service,token去Adapter中獲取對應的資訊。

func (e *Enforcer) ParseTempToken(service string, tempToken string) string {
	if tempToken == "" {
		return ""
	}
	return e.getByTempToken(service, tempToken)
}

刪除臨時token

https://github.com/weloe/token-go/blob/90e576f01537c92b924670dee3e32b8d7f010585/enforcer_manager_api.go#L248

刪除臨時token則是從Adapter元件中刪除對應的k,v資料

func (e *Enforcer) DeleteTempToken(service string, tempToken string) error {
	return e.deleteByTempToken(service, tempToken)
}

測試

func TestEnforcer_TempToken(t *testing.T) {
	enforcer, _ := NewTestEnforcer(t)
	service := "code"
	tempToken, err := enforcer.CreateTempToken("tempToken", service, "1234", -1)
	if err != nil {
		t.Fatalf("CreateTempToken() failed: %v", err)
	}
	if !reflect.DeepEqual(tempToken, "tempToken") {
		t.Fatalf("token error, want is %v", "1234")
	}
	timeout := enforcer.GetTempTokenTimeout(service, tempToken)
	if timeout != -1 {
		t.Errorf("GetTempTokenTimeout() failed, unexpected timeout: %v", timeout)
	}
	codeValue := enforcer.ParseTempToken("code", tempToken)
	if codeValue != "1234" {
		t.Errorf("ParseTempToken() failed, unexpected codeValue: %v", codeValue)
	}

	// delete
	if enforcer.DeleteTempToken(service, tempToken) != nil {
		t.Fatalf("DeleteTempToken() failed: %v", err)
	}
	tokenTimeout := enforcer.GetTempTokenTimeout(service, tempToken)
	if tokenTimeout != -2 {
		t.Errorf("GetTempTokenTimeout() failed, unexpected tokenTimeout: %v", tokenTimeout)
	}
	codeValue = enforcer.ParseTempToken(service, tempToken)
	if codeValue != "" {
		t.Errorf("ParseTempToken() failed, unexpected codeValue: %v", codeValue)
	}

	// create token
	tempToken, err = enforcer.CreateTempTokenByStyle("uuid", service, "1234", -1)
	if err != nil {
		t.Fatalf("CreateTempTokenByStyle() failed: %v", err)
	}
	// delete
	if enforcer.DeleteTempToken(service, tempToken) != nil {
		t.Fatalf("DeleteTempToken() failed: %v", err)
	}
}
--- PASS: TestEnforcer_TempToken (0.01s)
PASS