Gin中使用jwt:發放token、中間件鑒權
jwt,github地址:
https://github.com/dgrijalva/jwt-go/
前端返回結果的token分析:
//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjYsImV4cCI6MTYzNzY2Nzk5OCwiaWF0IjoxNjM3MDYzMTk4LCJpc3MiOiJjaGVuZ3FpYW5nIiwic3ViIjoidXNlciB0b2tlbiJ9.nt8K7vxrAT4XXzh0RbtFveQCyt7J4r1XZnVgDNSVjkQ
//token由三部分組成
//加密協議、荷載(程序信息)、前面兩部分+自定義密匙組成的一個哈希值
//使用base64解密保存的信息(分三段進行解密) : echo eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 | base64 -D
jwt配置:common/jwt.go
package common
import (
"github.com/dgrijalva/jwt-go"
"supplierQuerySystemAPICode/model"
"time"
)
//定義秘鑰
var jwtKey = []byte("*******")
type Claims struct {
UserId uint
jwt.StandardClaims
}
//登錄成功之后發放token
func ReleaseToken(user model.User) (string, error) {
expirationTime := time.Now().Add(7 * 24 * time.Hour) //token的有效期是七天
claims := &Claims{
UserId: user.ID,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expirationTime.Unix(), //token的有效期
IssuedAt: time.Now().Unix(), //token發放的時間
Issuer: "chengqiang", //作者
Subject: "user token", //主題
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(jwtKey) //根據前面自定義的jwt秘鑰生成token
if err != nil {
//返回生成的錯誤
return "", err
}
//返回成功生成的字符換
return tokenString, nil
}
//eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOjYsImV4cCI6MTYzNzY2Nzk5OCwiaWF0IjoxNjM3MDYzMTk4LCJpc3MiOiJjaGVuZ3FpYW5nIiwic3ViIjoidXNlciB0b2tlbiJ9.nt8K7vxrAT4XXzh0RbtFveQCyt7J4r1XZnVgDNSVjkQ
//token由三部分組成
//加密協議、荷載(程序信息)、前面兩部分+自定義密匙組成的一個哈希值
//使用base64解密保存的信息(分三段進行解密) : echo eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 | base64 -D
//解析從前端獲取到的token值
func ParseToken(tokenString string) (*jwt.Token, *Claims, error) {
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
return jwtKey, nil
})
return token, claims, err
}
中間件判斷前端獲取的請求信息,驗證通過,獲取用戶信息id,存入上下文中
package middleware
import (
"fmt"
"github.com/gin-gonic/gin"
"strings"
"supplierQuerySystemAPICode/common"
"supplierQuerySystemAPICode/model"
)
//路由請求中間件,前端必須把token放在請求頭上,對服務器進行請求驗證token成功后,才能訪問后續的請求路由
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 獲取 authorization header:獲取前端傳過來的信息的
tokenString := c.GetHeader("Authorization")
fmt.Print("請求token", tokenString)
//驗證前端傳過來的token格式,不為空,開頭為Bearer
if tokenString == "" || !strings.HasPrefix(tokenString, "Bearer ") {
c.JSON(401, gin.H{
"data": gin.H{
},
"meta": gin.H{
"msg": "權限不足",
"code": 401,
},
})
return
}
//驗證通過,提取有效部分(除去Bearer)
tokenString = tokenString[7:] //截取字符
//解析token:common/jwt.go
token, claims, err := common.ParseToken(tokenString)
//解析失敗||解析后的token無效
if err != nil || !token.Valid {
c.JSON(401, gin.H{
"data": gin.H{
},
"meta": gin.H{
"msg": "權限不足",
"code": 401,
},
})
return
}
//token通過驗證, 獲取claims中的UserID
userId := claims.UserId
var user model.User
//查詢數據庫
common.DB.First(&user, userId)
// 驗證用戶是否存在
if user.ID == 0 {
c.JSON(401, gin.H{
"data": gin.H{
},
"meta": gin.H{
"msg": "權限不足",
"code": 401,
},
})
}
//用戶存在 將user信息寫入上下文
c.Set("user", user)
c.Next()
}
}
