Golang中如何进行JWT权限验证与解析操作?

2026-05-22 06:261阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计983个文字,预计阅读时间需要4分钟。

Golang中如何进行JWT权限验证与解析操作?

JWT校验配置文件package configtype JWTstruct { SigningKey string `json:signingKey yaml:signing-key` ExpiresTime int64 `json:expiresTime yaml:expires-time` Issuer string `json:issuer yaml:issuer`}

Golang中如何进行JWT权限验证与解析操作?

JWT校验 配置文件

package config type JWT struct { SigningKey string `json:"signingKey" yaml:"signing-key"` // jwt签名 ExpiresTime int64 `json:"expiresTime" yaml:"expires-time"` // 过期时间 Issuer string `json:"issuer" yaml:"issuer"` // 签发者 } 工具结构体

package pkg import ( "errors" "time" "catering/global" "catering/model/system/request" "github.com/dgrijalva/jwt-go" ) type JWT struct { SigningKey []byte } var ( ErrTokenExpired = errors.New("token is expired") ErrTokenNotValidYet = errors.New("token not active yet") ErrTokenMalformed = errors.New("that's not even a token") ErrTokenInvalid = errors.New("couldn't handle this token") ) func NewJWT() *JWT { return &JWT{ []byte(global.Config.JWT.SigningKey), } } //生成claims func (j *JWT) CreateClaims(baseClaims request.BaseClaims) request.CustomClaims { claims := request.CustomClaims{ BaseClaims: baseClaims, StandardClaims: jwt.StandardClaims{ NotBefore: time.Now().Unix() - 1000, // 签名生效时间 ExpiresAt: time.Now().Unix() + global.Config.JWT.ExpiresTime, // 过期时间 7天 配置文件 Issuer: global.Config.JWT.Issuer, // 签名的发行者 }, } return claims } // 创建一个token func (j *JWT) CreateToken(claims request.CustomClaims) (string, error) { //对token进行签名加密 token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(j.SigningKey) } // CreateTokenByOldToken 旧token 换新token 用concurrency_control对token进行加锁避免并发问题(加锁粒度为oldToken) func (j *JWT) CreateTokenByOldToken(oldToken string, claims request.CustomClaims) (string, error) { v, err, _ := global.Concurrency_Control.Do("JWT:"+oldToken, func() (interface{}, error) { return j.CreateToken(claims) }) return v.(string), err } // 解析 token func (j *JWT) ParseToken(tokenString string) (*request.CustomClaims, error) { token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) { return j.SigningKey, nil }) if err != nil { if ve, ok := err.(*jwt.ValidationError); ok { if ve.Errors&jwt.ValidationErrorMalformed != 0 { return nil, ErrTokenMalformed } else if ve.Errors&jwt.ValidationErrorExpired != 0 { // Token is expired return nil, ErrTokenExpired } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { return nil, ErrTokenNotValidYet } else { return nil, ErrTokenInvalid } } } if token != nil { if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid { return claims, nil } return nil, ErrTokenInvalid } else { return nil, ErrTokenInvalid } } 使用 登录获取token

func (b *BaseApi) Login(c *gin.Context) { var l systemReq.Login msg, err := valid.BindAndValid(c, &l) if err != nil { response.FailWithMessage(msg, c) return } if store.Verify(l.CaptchaId, l.Captcha, true) { u := &system.SysUser{Username: l.Username, Password: l.Password} if err, user := userService.Login(u); err != nil { global.Log.Error("登陆失败! 用户名不存在或者密码错误!", zap.Error(err)) response.FailWithMessage("用户名不存在或者密码错误", c) } else { //登录成功,生成token b.tokenNext(c, *user) } } else { response.FailWithMessage("验证码错误", c) } } // 登录以后签发jwt func (b *BaseApi) tokenNext(c *gin.Context, user system.SysUser) { j := pkg.NewJWT() //新建claims claims := j.CreateClaims(systemReq.BaseClaims{ UUID: user.UUID, ID: uint(user.ID), NickName: user.NickName, Username: user.Username, AuthorityId: user.AuthorityId, }) //生成token token, err := j.CreateToken(claims) if err != nil { global.Log.Error("获取token失败!", zap.Error(err)) response.FailWithMessage("获取token失败", c) return } //生成session session, err := global.SESSION.Get(c.Request, "SessionId") if err != nil { fmt.Println(err) } session.Values["token"] = token //把session数据存放到cookie并在response的head中返回 session.Save(c.Request, c.Writer) //返回token response.OkWithDetailed(systemRes.LoginResponse{ User: user, Token: token, ExpiresAt: claims.StandardClaims.ExpiresAt * 1000, }, "登录成功", c) return } 在中间件中进行校验

package middleware import ( "strconv" "time" "catering/pkg" "catering/global" "catering/model/common/response" "github.com/gin-gonic/gin" ) func JWTAuth() gin.HandlerFunc { return func(c *gin.Context) { // 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 token := c.Request.Header.Get("x-token") if token == "" { response.FailWithDetailed(gin.H{"reload": true}, "未登录或非法访问", c) c.Abort() return } // 获取session session, _ := global.SESSION.Get(c.Request, "SessionId") t := session.Values["token"] //判断session和对session中的token进行比对 if tk, ok := t.(string); !ok { response.FailWithDetailed(gin.H{"reload": true}, "授权已过期", c) c.Abort() return } else if tk != token { response.FailWithDetailed(gin.H{"reload": true}, "授权已过期", c) c.Abort() return } j := pkg.NewJWT() // parseToken 解析token包含的信息 // 判断该token是否已经到达有效期 claims, err := j.ParseToken(token) if err != nil { if err == pkg.ErrTokenExpired { response.FailWithDetailed(gin.H{"reload": true}, "授权已过期", c) c.Abort() return } response.FailWithDetailed(gin.H{"reload": true}, err.Error(), c) c.Abort() return } //把解析出来的用户数据存入上下文中,方便后续的调用 c.Set("claims", claims) c.Next() } } 用法

//获取用户动态路由,返回包括系统菜单详情列表 func (a *AuthorityMenuApi) GetMenu(c *gin.Context) { //其中pkg.GetUserAuthorityId是通过上下文获取,也就是ctx.Get("claims") if err, menus := menuService.GetMenuTree(pkg.GetUserAuthorityId(c)); err != nil { global.Log.Error("获取失败!", zap.Error(err)) response.FailWithMessage("获取失败", c) } else { if menus == nil { menus = []system.SysMenu{} } response.OkWithDetailed(systemRes.SysMenusResponse{Menus: menus}, "获取成功", c) } } // pakcage pkg // 从Gin的Context中获取从jwt解析出来的用户角色id func GetUserAuthorityId(c *gin.Context) string { if claims, exists := c.Get("claims"); !exists { if cl, err := GetClaims(c); err != nil { return "" } else { return cl.AuthorityId } } else { waitUse := claims.(*systemReq.CustomClaims) return waitUse.AuthorityId } }

本文共计983个文字,预计阅读时间需要4分钟。

Golang中如何进行JWT权限验证与解析操作?

JWT校验配置文件package configtype JWTstruct { SigningKey string `json:signingKey yaml:signing-key` ExpiresTime int64 `json:expiresTime yaml:expires-time` Issuer string `json:issuer yaml:issuer`}

Golang中如何进行JWT权限验证与解析操作?

JWT校验 配置文件

package config type JWT struct { SigningKey string `json:"signingKey" yaml:"signing-key"` // jwt签名 ExpiresTime int64 `json:"expiresTime" yaml:"expires-time"` // 过期时间 Issuer string `json:"issuer" yaml:"issuer"` // 签发者 } 工具结构体

package pkg import ( "errors" "time" "catering/global" "catering/model/system/request" "github.com/dgrijalva/jwt-go" ) type JWT struct { SigningKey []byte } var ( ErrTokenExpired = errors.New("token is expired") ErrTokenNotValidYet = errors.New("token not active yet") ErrTokenMalformed = errors.New("that's not even a token") ErrTokenInvalid = errors.New("couldn't handle this token") ) func NewJWT() *JWT { return &JWT{ []byte(global.Config.JWT.SigningKey), } } //生成claims func (j *JWT) CreateClaims(baseClaims request.BaseClaims) request.CustomClaims { claims := request.CustomClaims{ BaseClaims: baseClaims, StandardClaims: jwt.StandardClaims{ NotBefore: time.Now().Unix() - 1000, // 签名生效时间 ExpiresAt: time.Now().Unix() + global.Config.JWT.ExpiresTime, // 过期时间 7天 配置文件 Issuer: global.Config.JWT.Issuer, // 签名的发行者 }, } return claims } // 创建一个token func (j *JWT) CreateToken(claims request.CustomClaims) (string, error) { //对token进行签名加密 token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(j.SigningKey) } // CreateTokenByOldToken 旧token 换新token 用concurrency_control对token进行加锁避免并发问题(加锁粒度为oldToken) func (j *JWT) CreateTokenByOldToken(oldToken string, claims request.CustomClaims) (string, error) { v, err, _ := global.Concurrency_Control.Do("JWT:"+oldToken, func() (interface{}, error) { return j.CreateToken(claims) }) return v.(string), err } // 解析 token func (j *JWT) ParseToken(tokenString string) (*request.CustomClaims, error) { token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) { return j.SigningKey, nil }) if err != nil { if ve, ok := err.(*jwt.ValidationError); ok { if ve.Errors&jwt.ValidationErrorMalformed != 0 { return nil, ErrTokenMalformed } else if ve.Errors&jwt.ValidationErrorExpired != 0 { // Token is expired return nil, ErrTokenExpired } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { return nil, ErrTokenNotValidYet } else { return nil, ErrTokenInvalid } } } if token != nil { if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid { return claims, nil } return nil, ErrTokenInvalid } else { return nil, ErrTokenInvalid } } 使用 登录获取token

func (b *BaseApi) Login(c *gin.Context) { var l systemReq.Login msg, err := valid.BindAndValid(c, &l) if err != nil { response.FailWithMessage(msg, c) return } if store.Verify(l.CaptchaId, l.Captcha, true) { u := &system.SysUser{Username: l.Username, Password: l.Password} if err, user := userService.Login(u); err != nil { global.Log.Error("登陆失败! 用户名不存在或者密码错误!", zap.Error(err)) response.FailWithMessage("用户名不存在或者密码错误", c) } else { //登录成功,生成token b.tokenNext(c, *user) } } else { response.FailWithMessage("验证码错误", c) } } // 登录以后签发jwt func (b *BaseApi) tokenNext(c *gin.Context, user system.SysUser) { j := pkg.NewJWT() //新建claims claims := j.CreateClaims(systemReq.BaseClaims{ UUID: user.UUID, ID: uint(user.ID), NickName: user.NickName, Username: user.Username, AuthorityId: user.AuthorityId, }) //生成token token, err := j.CreateToken(claims) if err != nil { global.Log.Error("获取token失败!", zap.Error(err)) response.FailWithMessage("获取token失败", c) return } //生成session session, err := global.SESSION.Get(c.Request, "SessionId") if err != nil { fmt.Println(err) } session.Values["token"] = token //把session数据存放到cookie并在response的head中返回 session.Save(c.Request, c.Writer) //返回token response.OkWithDetailed(systemRes.LoginResponse{ User: user, Token: token, ExpiresAt: claims.StandardClaims.ExpiresAt * 1000, }, "登录成功", c) return } 在中间件中进行校验

package middleware import ( "strconv" "time" "catering/pkg" "catering/global" "catering/model/common/response" "github.com/gin-gonic/gin" ) func JWTAuth() gin.HandlerFunc { return func(c *gin.Context) { // 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 token := c.Request.Header.Get("x-token") if token == "" { response.FailWithDetailed(gin.H{"reload": true}, "未登录或非法访问", c) c.Abort() return } // 获取session session, _ := global.SESSION.Get(c.Request, "SessionId") t := session.Values["token"] //判断session和对session中的token进行比对 if tk, ok := t.(string); !ok { response.FailWithDetailed(gin.H{"reload": true}, "授权已过期", c) c.Abort() return } else if tk != token { response.FailWithDetailed(gin.H{"reload": true}, "授权已过期", c) c.Abort() return } j := pkg.NewJWT() // parseToken 解析token包含的信息 // 判断该token是否已经到达有效期 claims, err := j.ParseToken(token) if err != nil { if err == pkg.ErrTokenExpired { response.FailWithDetailed(gin.H{"reload": true}, "授权已过期", c) c.Abort() return } response.FailWithDetailed(gin.H{"reload": true}, err.Error(), c) c.Abort() return } //把解析出来的用户数据存入上下文中,方便后续的调用 c.Set("claims", claims) c.Next() } } 用法

//获取用户动态路由,返回包括系统菜单详情列表 func (a *AuthorityMenuApi) GetMenu(c *gin.Context) { //其中pkg.GetUserAuthorityId是通过上下文获取,也就是ctx.Get("claims") if err, menus := menuService.GetMenuTree(pkg.GetUserAuthorityId(c)); err != nil { global.Log.Error("获取失败!", zap.Error(err)) response.FailWithMessage("获取失败", c) } else { if menus == nil { menus = []system.SysMenu{} } response.OkWithDetailed(systemRes.SysMenusResponse{Menus: menus}, "获取成功", c) } } // pakcage pkg // 从Gin的Context中获取从jwt解析出来的用户角色id func GetUserAuthorityId(c *gin.Context) string { if claims, exists := c.Get("claims"); !exists { if cl, err := GetClaims(c); err != nil { return "" } else { return cl.AuthorityId } } else { waitUse := claims.(*systemReq.CustomClaims) return waitUse.AuthorityId } }