(4)go web开发之 JWT-Token认证机制Access Token与Refresh Token及 jwt-go 库介绍及在项目中使用

介绍

  • jwt认证,参考文章:https://www.cnblogs.com/qtiger/p/14868110.html

  • 以前记录python 项目的时候,就已经有过相关的 session,cookie,jwt token的笔记了。 这里再来记录go的使用。
    在这里插入图片描述

  • jwt-go:

  • 查看文档,官方给了好几个例子:
    在这里插入图片描述

    • 可以使用这个方法,NewWithClains(CustomclaimsType)。 一般Go语言的方法命名习惯,都是这种 with … 说明是附加的可以使用相关的参数New。
    • func NewWithClaims(method SigningMethod, claims Claims) Token
      • 需要两个参数:

        • 第一个参数是一个加密的方法
        • 第二个参数是 一个接口: Claims
        • type Claims
          在这里插入图片描述
          • 下面这个方法实现了这个接口:是一个map类型。
          // Claims type that uses the map[string]interface{} for JSON decoding
          // This is the default claims type if you don't supply one
          type MapClaims map[string]interface{}
          
          • 还有
            在这里插入图片描述
      • 上面俩一个是 结构体形式,一个是map形式。都可以使用

      • 公有字段:jwt的 payload

      • 点击链接也可以查看:https://tools.ietf.org/html/rfc7519#section-4.1 这个标准下。
        在这里插入图片描述

      // Structured version of Claims Section, as referenced at
      // https://tools.ietf.org/html/rfc7519#section-4.1
      // See examples for how to use this with your own claim types
      type StandardClaims struct {
      	Audience  string `json:"aud,omitempty"`
      	// 过期时间 
      	ExpiresAt int64  `json:"exp,omitempty"`
      	Id        string `json:"jti,omitempty"`
      	IssuedAt  int64  `json:"iat,omitempty"`
      	// 签发人
      	Issuer    string `json:"iss,omitempty"`
      	// 什么时间开始生效
      	NotBefore int64  `json:"nbf,omitempty"`
      	Subject   string `json:"sub,omitempty"`
      }
      
  • 点击官方的方法介绍: 使用自定义类型声明令牌的示例。

    // 定义加密 秘钥
    mySigningKey := []byte("AllYourBase")
    
    // 自定义结构体数据, 并继承 内置的,标准的一些数据参数
    type MyCustomClaims struct {
    	Foo string `json:"foo"`
    	jwt.StandardClaims // 标准自带参数
    }
    
    // Create the Claims
    claims := MyCustomClaims{
    	"bar",
    	// 添加过期时间以及签发人
    	jwt.StandardClaims{
    		// 过期时间
    		ExpiresAt: 15000,
    		Issuer:    "test",
    	},
    }
    // 生成令牌token
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    // 加密
    ss, err := token.SignedString(mySigningKey)
    fmt.Printf("%v %v", ss, err)
    

解密

  • 还是开头的Examples里面, 看到下面这里: ParseWithClaims 方法

    func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error)
    
    • 其中 Keyfunc
      在这里插入图片描述
    • 中文解释: 解析方法使用此回调函数提供密钥以进行验证。函数接收已解析但未验证的令牌。这允许您使用令牌头中的属性(例如’kid’)来标识要使用的密钥。
  • 然后可以直接看官方的例子了:

    tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
    type MyCustomClaims struct {
    	Foo string `json:"foo"`
    	jwt.StandardClaims
    }
    
    // sample token is expired.  override time so it parses as valid
    token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
    	// 只返回加密的秘钥
    	return []byte("AllYourBase"), nil
    })
    
    if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
    	fmt.Printf("%v %v", claims.Foo, claims.StandardClaims.ExpiresAt)
    } else {
    	fmt.Println(err)
    }
    
  • 解析的过程中,如果key过期或者是 相关信息 和加密时候不一样,那么就会报错了,自动解析时,进行验证。

  • 对于使用解析出来的 token, 上面例子用已经有了

    • claims, ok := token.Claims.(*MyCustomClaims)。断言一下,变为自定义的类型,然后就可以读取其中的数值了。

gin项目 中使用

  • 利用中间件,做一个拦截器。接收验证token信息。

  • token 是前端放入 header 请求头中携带过来的。

    • token 有三种存放方式: 第一种是存放在 header 请求头当中,第二种是放到请求体当中,第三种就是放入到 URI 中。
  • 具体可以看开头给出的视频,最后部分讲解的实际项目中应用~。

  • 那么在我自己的小项目中,其实就是示例上的那种简单应用,生成token和解析token

    package jwt
    
    import (
    	"errors"
    	"time"
    
    	"github.com/golang-jwt/jwt"
    )
    
    // 定义 token 生效时间
    const TokenExpireOuration = time.Hour * 2
    
    // 定义秘钥
    var mySecret = []byte("这是加密的字符串")
    
    // 定义自己的 载体,并继承共有字段, 实现Claims接口
    type MyCustomClaims struct {
    	UserID   int64  `json:"user_id"`
    	Username string `json:"username"`
    	jwt.StandardClaims
    }
    
    // 封装生成Token的函数
    func GenToken(userID int64, username string) (string, error) {
    	// Create the Claims
    	claims := MyCustomClaims{
    		userID,
    		username,
    		jwt.StandardClaims{
    			// 指定过期时间
    			ExpiresAt: time.Now().Add(TokenExpireOuration).Unix(),
    			// 签发人: 写上项目名
    			Issuer: "HdlBluebell",
    		},
    	}
    	// 创建token
    	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    	// 使用指定的secret签名并获得完整的编码后的字符串token
    	tokenStr, err := token.SignedString(mySecret)
    	return tokenStr, err
    }
    
    // 解析token字符串
    func ParseToken(tokenString string) (*MyCustomClaims, error) {
    	// 调用解析函数
    	token, err := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
    		// 只返回加密的秘钥
    		return []byte("AllYourBase"), nil
    	})
    	if err != nil {
    		return nil, err
    	}
    	// 拿到 MyCustomClaims 类型的结构
    	// Claims 接口实现了 Valid() 方法, 对数据进行验证
    	if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
    		return claims, nil
    	} else {
    		return nil, errors.New("invalid token")
    	}
    }
    
    
  • 采用 HTTP Bearer认证https://www.cnblogs.com/qtiger/p/14868110.html这篇文章开头给出过。

  • 这种方式在 Postman 当中进行测试的时候,也有对应的:
    在这里插入图片描述

  • 定义 JWT 认证中间件:

    • 其中的controllers.ResponseError(c, controllers.CodeNeedLogin) 是返回请求的 c.JSON() 只是被封装了一下,代码更加的简洁。
    package main
    
    import (
    	"bluebell/controllers"
    	"bluebell/pkg/jwt"
    	"strings"
    
    	"github.com/gin-gonic/gin"
    )
    
    // 当认证通过后, 保存到当前的定义的上下文信息当中去
    const ContextUserIDKey = "userID"
    
    func JWTAuthMiddleware() func(c *gin.Context) {
    	return func(c *gin.Context) {
    		// HTTP Bearer: https://www.cnblogs.com/qtiger/p/14868110.html#autoid-3-4-0
    		// 在 http 请求头当中添加 Authorization: Bearer (token) 字段完成验证
    		// 1. 获取请求头中的 Authorization 认证字段信息
    		authStr := c.Request.Header.Get("Authorization")
    		// 2.
    		if authStr == "" {
    			controllers.ResponseError(c, controllers.CodeNeedLogin)
    			// 停止后序的 handler 处理函数执行,并终止当前后续操作
    			c.Abort()
    			return
    		}
    		// 切分, 格式不对,报错
    		p := strings.Split(authStr, " ")
    		if len(p) != 2 || p[0] != "Bearer" {
    			controllers.ResponseError(c, controllers.CodeInvalidToken)
    		}
    		// 3. 解析token
    		m, err := jwt.ParseToken(p[1])
    		if err != nil {
    			controllers.ResponseError(c, controllers.CodeInvalidToken)
    			c.Abort()
    			return
    		}
    		// 保存当前登录的用户信息,存入context 上下文当中去,并继续向下执行
    		c.Set(ContextUserIDKey, m.UserID)
    		c.Next()
    	}
    }
    

下面采用 Access Token, Refresh Token 双刷,实现 认证。

  • 可以参考这篇文章中的内容: https://blog.csdn.net/a704397849/article/details/90216739

  • Access Token: 访问后端接口的请求 token。为了安全性,有效期通常较短, 因为只要在有效期内获取token, 都可以对后端资源进行请求访问。

  • Refresh Token: 有效期较长。 当 Access Token 过期的时候, 用Refresh Token 就可以获取到新的 Access Token。保证了用户的体验性和安全性。不需要频繁的 token过期而 重新登录。 只有在 Refresh Token 过期的时候,才会去重新进行登录的操作。

  • 生成 refresh token

    // 生成 refresh token, 不需要自定义的信息
    	rToken, err = jwt.NewWithClaims(jwt.SigningMethodES256, jwt.StandardClaims{
    		ExpiresAt: time.Now().Add(time.Second * 30).Unix(),
    		Issuer:    "HdlBluebell",
    	}).SignedString(mySecret)
    
  • 另外就是解析时候判断access token 是否有效。refresh token 刷新 access token。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要解析jwt-go的token,可以按照以下步骤进行操作: 1. 首先,引入`jwt-go`包并导入所需的其他依赖项。可以使用以下代码来实现: ``` import ( "fmt" "github.com/dgrijalva/jwt-go" ) ``` 2. 然后,定义自定义声明结构体,该结构体包含要在token解析的声明信息。例如,可以定义一个名为`MyCustomClaims`的结构体,如下所示: ``` type MyCustomClaims struct { Foo string `json:"foo"` jwt.StandardClaims } ``` `MyCustomClaims`结构体的`Foo`字段表示在token包含的自定义声明。 3. 接下来,使用`jwt.ParseWithClaims`函数解析token并将其与自定义声明结构体进行绑定。可以使用以下代码实现: ``` tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6I***XVCJ9.eyJmb28iOiJiY***iLCJleHAiOjE1***AwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c" claims := &MyCustomClaims{} token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { // 返回用于验证token的加密密钥 return []byte("AllYourBase"), nil }) ``` 在`jwt.ParseWithClaims`函数,传入token字符串、自定义声明结构体的指针和一个回调函数。回调函数用于提供用于验证token的加密密钥。 4. 最后,检查解析和验证token的结果。可以使用以下代码来检查是否成功解析和验证了token: ``` if token.Valid { fmt.Printf("%v %v", claims.Foo, claims.ExpiresAt) } else { fmt.Println(err) } ``` 如果token有效,可以通过`claims`变量访问其的声明信息。在上述示例,我们打印了`Foo`字段和`ExpiresAt`声明的值。如果token无效,将打印出解析和验证错误。 综上所述,这就是解析`jwt-go`的token的步骤。请注意,需要根据自己的实际情况修改代码token字符串和自定义声明结构体。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [(4)go web开发JWT-Token认证机制Access TokenRefresh Tokenjwt-go 介绍及在项目使用](https://blog.csdn.net/pythonstrat/article/details/121875782)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值