Golang实现自定义JWT生成与验证
需要用到的包
import ( "errors" "gin_web/app/models/admin" "gin_web/config" "github.com/dgrijalva/jwt-go" )
首先自定义结构体并继承jwt.StandardClaims
// Claims 自定义声明结构体并内嵌jwt.StandardClaims type CustomClaims struct { UserID uint64 `json:"user_id"` jwt.StandardClaims } func NewCustomClaims(userID uint64) CustomClaims { return CustomClaims{ userID, jwt.StandardClaims{ ExpiresAt: config.Jwt.ExpiresAt, Issuer: config.Jwt.Issuer, }, } }
生成jwt与验证的方法
// GenerateToken 生成JWT func GenerateToken(claims jwt.Claims) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // 生成签名字符串 tokenStr, err := token.SignedString([]byte(config.Jwt.SecretKey)) if err != nil { return "", err } return tokenStr, nil } // ParseToken 解析JWT func ParseToken(tokenString string, claims jwt.Claims) error { token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { return []byte(config.Jwt.SecretKey), nil }) if err != nil { return err } // 对token对象中的Claim进行类型断言 if token.Valid { // 校验token return nil } return errors.New("invalid token") }
整体代码
package jwtutils import ( "errors" "gin_web/app/models/admin" "gin_web/config" "github.com/dgrijalva/jwt-go" ) // Claims 自定义声明结构体并内嵌jwt.StandardClaims type CustomClaims struct { UserID uint64 `json:"user_id"` jwt.StandardClaims } func NewCustomClaims(userID uint64) CustomClaims { return CustomClaims{ userID, jwt.StandardClaims{ ExpiresAt: config.Jwt.ExpiresAt, Issuer: config.Jwt.Issuer, }, } } // GenerateToken 生成JWT func GenerateToken(claims jwt.Claims) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // 生成签名字符串 tokenStr, err := token.SignedString([]byte(config.Jwt.SecretKey)) if err != nil { return "", err } return tokenStr, nil } // ParseToken 解析JWT func ParseToken(tokenString string, claims jwt.Claims) error { token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { return []byte(config.Jwt.SecretKey), nil }) if err != nil { return err } // 对token对象中的Claim进行类型断言 if token.Valid { // 校验token return nil } return errors.New("invalid token") }
声明后台结构体自定义内容格式,并使用
jwtutils包中定义如下代码
// AdminCustomClaims 自定义格式内容 type AdminCustomClaims struct { AdminInfo *admin.AdminModel jwt.StandardClaims // 内嵌标准的声明 } // NewAdminCustomClaims 初始化AdminCustomClaims func NewAdminCustomClaims(userInfo *admin.AdminModel, expiresAt int64) AdminCustomClaims { return AdminCustomClaims{ userInfo, jwt.StandardClaims{ ExpiresAt: expiresAt, Issuer: config.Jwt.Issuer, }, } }
login方法中使用
adminUserInfo, err := adminUserModel.FirstByUsername(params.UserName) //验证密码 if err != nil || !utils.PasswordVerify(params.PassWord, adminUserInfo.Password) { response.Error(ctx, "用户不存在或密码错误!", nil) return } //生成token claims := jwtutils.NewAdminCustomClaims(adminUserInfo, time.Now().Add(time.Hour*72).Unix()) tokenString, err := jwtutils.GenerateToken(claims) if err != nil { response.Error(ctx, "登录失败,Token生成失败!"+err.Error(), nil) return } go func() { //验证通过,更新登陆时间和ip,记录Session adminUserModel.Update(adminUserInfo.AdminId, map[string]interface{}{ "last_login_ip": ctx.ClientIP(), "last_login_time": time.Now().Format("2006-01-02 15:04:05"), }) }() response.Success(ctx, "登陆成功!", gin.H{ "token": tokenString, "nickname": adminUserInfo.Username, "avatar": adminUserInfo.Avatar, })
中间件验证token
package middleware import ( "errors" "gin_web/app/response" "gin_web/app/utils/jwtutils" "net/http" "strings" "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" ) // AdminAuthHandler后台认证 func AdminAuthHandler() gin.HandlerFunc { return func(c *gin.Context) { // 从请求头中获取 Authorization 字段 authHeader := c.GetHeader("Authorization") if authHeader == "" { response.AbortWithStatusJSON(c, http.StatusUnauthorized, "Unauthorized", nil, http.StatusAccepted) return } // 检查Bearer Token格式 parts := strings.Split(authHeader, " ") if len(parts) != 2 || parts[0] != "Bearer" { response.AbortWithStatusJSON(c, http.StatusUnauthorized, "The token format is incorrect", nil, http.StatusAccepted) return } // 验证Token tokenStr := parts[1] adminCustomClaims := &jwtutils.AdminCustomClaims{} if err := jwtutils.ParseToken(tokenStr, adminCustomClaims); err != nil { if errors.Is(err, jwt.ErrSignatureInvalid) { response.AbortWithStatusJSON(c, http.StatusUnauthorized, "Token verification failed", nil, http.StatusAccepted) } else { response.AbortWithStatusJSON(c, http.StatusUnauthorized, "Bad Request", nil, http.StatusAccepted) } return } // 将解析后的 claims 附加到上下文中,以便后续处理器使用 c.Set("adminId", adminCustomClaims.AdminInfo.AdminId) c.Set("username", adminCustomClaims.AdminInfo.Username) c.Set("roleId", adminCustomClaims.AdminInfo.RoleId) c.Set("adminInfo", adminCustomClaims.AdminInfo) c.Next() } }
-------------本文结束感谢您的阅读-------------