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()
}
}-------------本文结束感谢您的阅读-------------
