之前的總結
之前自己總結過使用Python實現JWT認證的博客:關於跨域與同源策略、安全cookie、CSRF與JWT認證校驗看這一篇就夠了
參考博客
主要參考這篇博客實現的,自己親自動手實現一下,加深一下印象:https://www.liwenzhou.com/posts/Go/jwt_in_gin/
進階的模塊
GitHub上有一個進階的模塊,里面有refreshToken以及auth認證等說明:https://github.com/appleboy/gin-jwt
自己的練習
需要先下載 jwt-go 這個模塊:
go get github.com/dgrijalva/jwt-go
gin框架中使用jwt認證代碼
package t_ginProjets import ( "errors" "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" "net/http" "strings" "testing" "time" ) // 用戶信息結構體 type User struct { Username string `json:"username"` Password string `json:"password"` } // MyClaims 自定義聲明結構體並內嵌jwt.StandardClaims // jwt包自帶的jwt.StandardClaims只包含了官方字段 // 我們這里需要額外記錄一個username字段,所以要自定義結構體 // 如果想要保存更多信息,都可以添加到這個結構體中 type MyClaims struct { Username string `json:"username"` jwt.StandardClaims } // 定義JWT的過期時間 設置2小時 const TokenExpireDuration = time.Hour * 2 // 定義一個secret var JWTSecret = []byte("GarfieldIsAHero!") // 1、生成JWT func GenToken(username string) (string, error) { c := MyClaims{ "wanghw", // 自定義的字段 jwt.StandardClaims{ ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 過期時間 Issuer: "jwt_test", // 簽發人 }, } // 使用指定的簽名方法創建簽名對象 token := jwt.NewWithClaims(jwt.SigningMethodHS256, c) // 使用指定的secret簽名並獲取完整的編碼后的字符串token return token.SignedString(JWTSecret) } // 2、解析JWT func ParseToken(tokenString string) (*MyClaims, error) { // 后面是一個匿名函數 token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) { return JWTSecret, nil }) if err != nil { return nil, err } // 校驗token if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { return claims, nil } return nil, errors.New("invalid token") } // 3、定義一條 authHandler用於token的認證 func authHandler(c *gin.Context) { // 用戶發送用戶名與密碼 var user User // 獲取參數 err := c.ShouldBind(&user) if err != nil { c.JSON(http.StatusOK, gin.H{ "code": 2002, "msg": "無效的參數", }) c.Abort() return } // 校驗用戶名與密碼是否正確 if user.Username != "whw" || user.Password != "666" { c.JSON(200, gin.H{ "code": 2001, "msg": "用戶名或密碼錯誤", }) c.Abort() return } // 生成Token tokenString, _ := GenToken(user.Username) c.JSON(200, gin.H{ "code": 2000, "msg": "success", "data": gin.H{"token": tokenString, "tokenExpire": 7200}, }) return } // 4、實現校驗的中間件 // JWTAuthMiddleware 基於JWT的認證中間件 func JWTAuthMiddleware() func(c *gin.Context) { return func(c *gin.Context) { // 客戶端攜帶Token有三種方式 1.放在請求頭 2.放在請求體 3.放在URI // 這里假設Token放在Header的Authorization中,並使用Bearer開頭 // 這里的具體實現方式要依據你的實際業務情況決定 authHeader := c.Request.Header.Get("Authorization") // 獲取請求頭中的數據 if authHeader == "" { c.JSON(http.StatusOK, gin.H{ "code": 2003, "msg": "請求頭中auth為空", }) // 不進行下面的請求處理了! c.Abort() return } // 按空格分割 parts := strings.SplitN(authHeader, " ", 2) if !(len(parts) == 2 && parts[0] == "Bearer") { c.JSON(http.StatusOK, gin.H{ "code": 2004, "msg": "請求頭中auth格式有誤", }) // 不進行下面的請求處理了! c.Abort() return } // parts[1]是獲取到的tokenString,我們使用之前定義好的解析JWT的函數來解析它 mc, err := ParseToken(parts[1]) if err != nil { c.JSON(http.StatusOK, gin.H{ "code": 2005, "msg": "無效的Token", }) // 不進行下面的請求處理了! c.Abort() return } // 將當前請求的username信息保存到請求的上下文c上 c.Set("username", mc.Username) c.Next() // 后續的處理函數可以用過c.Get("username")來獲取當前請求的用戶信息 } } // *** 開始測試 func TestJWTAuth(t *testing.T) { // 默認引擎 r := gin.Default() // 注冊路由 // 生成token的請求 r.POST("/auth", authHandler) // home路由需要注冊認證中間件 r.GET("/home", JWTAuthMiddleware(), homeHandler) // 啟動 r.Run("127.0.0.1:9100") } // home路由 func homeHandler(c *gin.Context) { // 獲取參數 username := c.MustGet("username").(string) // 返回響應 c.JSON(http.StatusOK, gin.H{ "code": 2000, "msg": "success", "data": gin.H{"username": username}, }) }
認證過程
啟動服務后,需要首先生成token,我這里使用postman測試:

生成token成功后,需要在auth頭中加入bearer token,token的具體值就是上面生成的那個:

~~~
