golang項目中加入token方式
什么是token
"token"指的是一種用于驗證用戶身份或授權(quán)訪問的憑證。這種類型的token在進行網(wǎng)絡(luò)身份驗證時非常常見,例如,在網(wǎng)站登錄時生成的身份驗證令牌或OAuth(開放授權(quán))協(xié)議中用于授權(quán)訪問資源的訪問令牌。
token一般在用戶登錄成功時由服務(wù)器端生成并隨數(shù)據(jù)一同發(fā)送給客戶端,由客戶端存儲token,并在再次發(fā)送請求時,在請求頭中帶上token并發(fā)送給客戶端。
為什么要加入token
試想一下,如果沒有token,任何游客都可以隨意的訪問系統(tǒng)內(nèi)的各個接口,那么系統(tǒng)的安全性就沒有辦法得到保障。惡意用戶可以利用管理員權(quán)限,隨意調(diào)用相關(guān)接口以獲取系統(tǒng)內(nèi)部信息,系統(tǒng)用戶信息,或者對系統(tǒng)端口進行網(wǎng)絡(luò)攻擊。
加入token以后,我們通過使用token進行授權(quán)可以實現(xiàn)細粒度的權(quán)限控制,因為每個token可以包含特定的訪問權(quán)限。這樣可以確保用戶只能訪問其被授權(quán)的資源,從而增強系統(tǒng)的安全性。
如何在go項目中部署token
那么,怎么在我們的go項目中部署token呢,當(dāng)然是利用成熟的go包。
首先在項目中需要導(dǎo)入JWT(JSON Web Token)數(shù)據(jù)包
go get github.com/golang-jwt/jwt/v4
然后編寫token生成函數(shù)
func GenerateJwt() string {
log := logrus.WithFields(logrus.Fields{
"func": "GenerateJwt",
})
token := jwt.New(jwt.SigningMethodHS256)
//jwt.New()創(chuàng)建一個新的JWT對象,使用HS256算法對其進行簽名
claims := make(jwt.MapClaims)
claims["exp"] = time.Now().Add(time.Hour * time.Duration(common.TokenDuration)).Unix()
claims["iat"] = time.Now().Unix()
token.Claims = claims
//創(chuàng)建JWT(JSON Web Token)的載荷部分,并聲明token的過期事件和創(chuàng)建時間。
tokenString, err := token.SignedString([]byte(common.SecretKey))
//使用密鑰對jwt進行簽名,并生成toekn字符串
if err != nil {
log.Errorf("GenerateJwt err:%v", err)
}
return tokenString
}
在函數(shù)中,使用log記錄函數(shù)中的錯誤信息,如果沒有記錄日志的需求,log也可以省略。
函數(shù)中claims用于存儲jwt的荷載信息,其中的exp和iat為jwt的標(biāo)準(zhǔn)聲明,表示token的過期時間,和創(chuàng)建時間。
- common.TokenDuration是一個整形常量,用于設(shè)定token存在時間。
- common.SecretKey為一個字符串常量,自己設(shè)定,表示對數(shù)據(jù)進行加密時用到的密鑰。
由于common.SecretKey只有設(shè)定者知道,除系統(tǒng)外,惡意用戶將無法對token進行解密。
編寫完token函數(shù),在用戶登錄成功時,應(yīng)該將token返回給用戶,用戶以token作為自身身份憑證。
if user.Phone != "" {
if judge := sql.IfadminPhone(c, &user, log); judge {
token := gentoken.GenerateJwt()//token生成函數(shù)
c.JSON(200, gin.H{"message": "Login successful", "token": token}) //返回給用戶token
return
}}
我們使用postman驗證token是否生成成功。
{
"message": "Login successful",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDkyNTkzMDQsImlhdCI6MTcwOTI1NTcwNH0.zc3DznaTQxOZMqlloS2dSAVC-AgbrE9FId2TQE03_uQ"
}
可以看到,登錄成功時服務(wù)器成功向用戶訪問了token
如何驗證token
那么,如何驗證token信息呢?除了登錄和注冊功能外,其他所有接口均需驗證token信息。
我在項目中使用到了gin框架,使用gin框架的中間件,可以方便的完成這個功能。
func Router() *gin.Engine {
r := gin.Default()
r.POST("/user/login", service.Login)
r.POST("/user/register", service.Register)
auth := r.Group("/")
auth.Use(gentoken.AuthMiddleware())
{
auth.GET("/index", service.GetIndex)
auth.GET("/user/getUserList", service.GetUserList)
auth.GET("/user/findUserByName", service.FindUserByName)
auth.GET("/user/delete", service.DeleteUser) //刪除指定用戶名的用戶
auth.POST("/user/update", service.UpdateUser)
//發(fā)送消息
auth.GET("/user/sendUserMsg", service.SendUserMsg)
auth.GET("/user/sendMsg", service.SendMsg)
}}
通過r.Group將除登錄注冊外的所有功能設(shè)置為一個auth組,并為該組成員添加中間件gentoken.AuthMiddleware()函數(shù)。
這樣,所有要訪問auth組的請求都需要經(jīng)過AuthMiddleware()函數(shù)驗證后才能獲取到服務(wù)。
在AuthMiddleware()函數(shù)中我們添加驗證token的請求:
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.AbortWithStatus(http.StatusUnauthorized)
return
}
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte(common.SecretKey), nil
})
if err == nil && token.Valid {
c.Next()
} else {
c.AbortWithStatus(http.StatusUnauthorized)
}
}
}
其中common.SecretKey為加密時使用的密鑰,此時要通過jwt.Parse()函數(shù)將其解密。
通過token.Valid驗證token是否過期,是否為系統(tǒng)簽發(fā)。
好了,現(xiàn)在token驗證機制已經(jīng)完成。
驗證
我們首先用postman發(fā)送不帶token的請求到系統(tǒng)服務(wù)。

發(fā)現(xiàn)系統(tǒng)無返回值。
在頭部帶上token后:

成功使用系統(tǒng)功能獲取到用戶信息。
好了,現(xiàn)在你可以在自己的項目里部署一個簡單的token來進行用戶身份驗證啦??!
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Go語言使用goroutine及通道實現(xiàn)并發(fā)詳解
這篇文章主要為大家介紹了Go語言使用goroutine及通道實現(xiàn)并發(fā)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08
Go1.21新增內(nèi)置函數(shù)(built-in?functions)詳解
Go?1.21新增的內(nèi)置函數(shù)分別是?min、max?和?clear,這篇文章主要帶大家一起了解一下這幾個函數(shù)的用途和使用示例,感興趣的小伙伴可以學(xué)習(xí)一下2023-08-08

