Gin + Ant Design Pro JWT认证

编程入门 行业动态 更新时间:2024-10-12 03:27:05

Gin + <a href=https://www.elefans.com/category/jswz/34/1754493.html style=Ant Design Pro JWT认证"/>

Gin + Ant Design Pro JWT认证

文章目录

  • 一:介绍
  • 二:Gin JWT 后台
    • 1. `Claims `定义
    • 2. 创建和解析Token
    • 3. Gin中间件编写
    • 4. 辅助函数
  • 三:Ant Design Pro JWT认证
  • 四:Gin中间件和使用示范

一:介绍

  • JWT现在比较流行的认证方式,微服务中使用特别常见。
  • JWT标准格式

在HTTP请求添加名为Authorization的header,形式如下: (token前面Bearer 是标准前缀字符串)
Authorization: Bearer

  • Go JWT 结构体Claims,可以理解为需要保存的信息,加密后会存储在token中,解密后会从token自动解析出来

配合ant design pro前端实现需要解决以下问题:

  • JWT TOKEN需要存储哪些字段以及定义,如何创建和解析
  • 前端发送请求时如何自动添加JWT认证信息
  • JWT TOKEN过期后,前后端如何配合自动刷新

二:Gin JWT 后台

使用库github/golang-jwt/jwt/v5

1. Claims 定义

jwt.RegisteredClaimsgithub/golang-jwt/jwt/v5预设的标准claims,后面用到其ExpiresAt过期时间字段,UserClaims 为自定义存储的字段,最终加密到token中的是jwtClaims结构

type UserClaims struct {
// 可以添加字段存储其他信息UserID   uint   `json:"userId"`RoleID   uint   `json:"roleId"`UserName string `json:"username"`
}type jwtClaims struct {UserClaimsjwt.RegisteredClaims
}

2. 创建和解析Token

expireHoursrefreshHours分别是设置过期时间,以及距离过期时间多久返回新token,后续在gin中间件中判断,方式是在Header中返回x-refresh-tokennewToken

type JWT struct {secret       []byteexpireHours  time.TimerefreshHours time.Duration
}// j := NewJWT("密钥", 2, 1)
// token过期时间是2小时, 距离过期时间还有1小时时在`Header`中返回`x-refresh-token`:`newToken`
func NewJWT(secret string, expireHours int, refreshHours int) *JWT {return &JWT{secret:       []byte(secret),expireHours:  time.Now().Add(time.Duration(expireHours) * time.Hour),refreshHours: time.Hour * time.Duration(refreshHours),}
}func (j *JWT) CreateToken(u UserClaims) (string, error) {token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtClaims{UserClaims: u,RegisteredClaims: jwt.RegisteredClaims{ExpiresAt: jwt.NewNumericDate(j.expireHours),IssuedAt:  jwt.NewNumericDate(time.Now()),},})return token.SignedString(j.secret)
}func (j *JWT) ParseToken(tokenString string) (*jwtClaims, error) {token, err := jwt.ParseWithClaims(tokenString, &jwtClaims{}, func(token *jwt.Token) (interface{}, error) {return j.secret, nil})if err != nil {return nil, err}if claims, ok := token.Claims.(*jwtClaims); ok && token.Valid {return claims, nil} else {return nil, errors.New("Token无效")}
}

3. Gin中间件编写

type BaseResponse struct {Success      bool   `json:"success"`Data         any    `json:"data"`Message      string `json:"message"`ErrorMessage string `json:"errorMessage"`
}func OkWithData(c *gin.Context, data any) {c.JSON(200, BaseResponse{Success: true, Data: data})
}func OkWithMsg(c *gin.Context, msg string) {c.JSON(200, BaseResponse{Success: true, Message: msg})
}func Fail(c *gin.Context, errMsg string) {c.JSON(200, BaseResponse{Success: false, ErrorMessage: errMsg})
}
// 使用如下:
// // token过期时间是2小时, 距离过期时间还有1小时时在`Header`中返回`x-refresh-token`:`newToken`
// j := NewJWT("密钥", 2, 1)
// r.USE(JWTAuth(j))
func JWTAuth(j *JWT) gin.HandlerFunc {return func(c *gin.Context) {token := c.Request.Header.Get("Authorization")token = strings.TrimPrefix(token, "Bearer ")claims, err := j.ParseToken(token)if err != nil {response.Fail(c, "Token错误: "+err.Error())c.Abort()return}if time.Since(claims.ExpiresAt.Local()) < j.refreshHours {newToken, err := j.CreateToken(claims.UserClaims)if err != nil {response.Fail(c, "Token刷新错误: "+err.Error())c.Abort()return}c.Header("x-refresh-token", newToken)}c.Set("claims", claims)c.Next()}}

4. 辅助函数

gin中直接调用该函数可以方便的获取到存储的机构体信息

func GetUserToken(c *gin.Context) *UserClaims {claims, _ := c.Get("claims")if claims == nil {return &UserClaims{}}return &claims.(*jwtClaims).UserClaims
}

三:Ant Design Pro JWT认证

处理登录请求后返回jwt token使用localStorage.setItem('jwt', token)存储起来
app.tsx的文件request定义中添加拦截器,实现方法:

  • 请求前,在header中添加头·Authorization·: 'Bearer ’ + localStorage.getItem(‘jwt’) || ‘’
  • 请求后,检测header中是否存在x-refresh-token,存在的话更新token,目的是防止token过期自动刷新
    实现如下:
function setToken(token: string) {localStorage.setItem('jwt', token);
}function getToken(): string {return localStorage.getItem('jwt') || '';
}export const request = {...errorConfig,// 请求前拦截器requestInterceptors: [(url: string, options: RequestConfig) => {const authHeader = { Authorization: 'Bearer ' + getToken() };return {url: `${url}`,options: { ...options, interceptors: true, headers: authHeader },};},],// 请求后拦截器responseInterceptors: [(response: Response, options: RequestConfig) => {if (response.headers.has('x-refresh-token')) {setToken(response.headers.get('x-refresh-token') || '');}return response;},],
};

四:Gin中间件和使用示范

jwt_middleware.go

package middlewareimport ("errors""strings""time""github/gin-gonic/gin""github/golang-jwt/jwt/v5"
)// 可以添加字段存储其他信息
type UserClaims struct {UserID   uint   `json:"userId"`RoleID   uint   `json:"roleId"`UserName string `json:"username"`
}type jwtClaims struct {UserClaimsjwt.RegisteredClaims
}type JWT struct {secret       []byteexpireHours  time.TimerefreshHours time.Duration
}// j := NewJWT("密钥", 2, 1)
// token过期时间是2小时, 距离过期时间还有1小时时在`Header`中返回`x-refresh-token`:`newToken`
func NewJWT(secret string, expireHours int, refreshHours int) *JWT {return &JWT{secret:       []byte(secret),expireHours:  time.Now().Add(time.Duration(expireHours) * time.Hour),refreshHours: time.Hour * time.Duration(refreshHours),}
}func (j *JWT) CreateToken(u UserClaims) (string, error) {token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtClaims{UserClaims: u,RegisteredClaims: jwt.RegisteredClaims{ExpiresAt: jwt.NewNumericDate(j.expireHours),IssuedAt:  jwt.NewNumericDate(time.Now()),},})return token.SignedString(j.secret)
}func (j *JWT) ParseToken(tokenString string) (*jwtClaims, error) {token, err := jwt.ParseWithClaims(tokenString, &jwtClaims{}, func(token *jwt.Token) (interface{}, error) {return j.secret, nil})if err != nil {return nil, err}if claims, ok := token.Claims.(*jwtClaims); ok && token.Valid {return claims, nil} else {return nil, errors.New("Token无效")}
}// 使用如下:
// // token过期时间是2小时, 距离过期时间还有1小时时在`Header`中返回`x-refresh-token`:`newToken`
// j := NewJWT("密钥", 2, 1)
// r.USE(JWTAuth(j))
func JWTAuth(j *JWT) gin.HandlerFunc {return func(c *gin.Context) {token := c.Request.Header.Get("Authorization")token = strings.TrimPrefix(token, "Bearer ")claims, err := j.ParseToken(token)if err != nil {response.Fail(c, "Token错误: "+err.Error())c.Abort()return}if time.Since(claims.ExpiresAt.Local()) < j.refreshHours {newToken, err := j.CreateToken(claims.UserClaims)if err != nil {response.Fail(c, "Token刷新错误: "+err.Error())c.Abort()return}c.Header("x-refresh-token", newToken)}c.Set("claims", claims)c.Next()}}func GetUserToken(c *gin.Context) *UserClaims {claims, _ := c.Get("claims")if claims == nil {return &UserClaims{}}return &claims.(*jwtClaims).UserClaims
}type BaseResponse struct {Success      bool   `json:"success"`Data         any    `json:"data"`Message      string `json:"message"`ErrorMessage string `json:"errorMessage"`
}func OkWithData(c *gin.Context, data any) {c.JSON(200, BaseResponse{Success: true, Data: data})
}func OkWithMsg(c *gin.Context, msg string) {c.JSON(200, BaseResponse{Success: true, Message: msg})
}func Fail(c *gin.Context, errMsg string) {c.JSON(200, BaseResponse{Success: false, ErrorMessage: errMsg})
}

main.go

package middlewareimport ("fmt""github/gin-gonic/gin"
)func main() {j := NewJWT("密钥", 2, 1)r := gin.Default()r.POST("/login", func(ctx *gin.Context) {// 处理登录逻辑返回token, 前端需讲token存储到localstoragetoken, err := j.CreateToken(UserClaims{UserID: 1, RoleID: 1, UserName: "Leo"})if err != nil {response.Fail(ctx, err.Error())return}response.OkWithData(ctx, gin.H{"token": token})})auth := r.Group("/api")auth.Use(JWTAuth(j))auth.GET("/test", func(ctx *gin.Context) {u := GetUserToken(ctx)response.OkWithMsg(ctx, fmt.Sprintf("用户ID:%d角色ID:%d用户名:%s", u.UserID, u.RoleID, u.UserName))})
}

更多推荐

Gin + Ant Design Pro JWT认证

本文发布于:2023-12-07 06:50:57,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1670458.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Ant   Gin   Design   JWT   Pro

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!