Golang中的JWT基础使用 | 青训营

1,623 阅读4分钟

写在前面

项目的具体开发,总是会有许许多多的问题暴露出来。但是路还是要一步一步走,今天来学习JWT的基础使用。

什么是JWT

在介绍JWT之前,我们先来了解一下什么是JSON。简单来说JSON是一种文本格式,但是它可以完全独立于编程语言来存储和表示数据。
JWT的英文全称是JSON Web Token,它可以让我们在用户与服务器之间传递安全可靠的JSON文本信息。具体来说,用户注册时,服务端会接收到来自用户在用户端输入的账号和密码,然后向客户端发送JWT。由此客户端有了JWT这个令牌。当下次客户端再向服务端请求数据时,只要利用这个令牌,就可以轻松地访问客户端的数据。这种信息传输方式有开销少传输安全等优点。

JWT的结构

JWT由三部分组成:

  • Header
  • Payload,声明
  • Signature,签名

Header由token的类型("JWT")和签名算法名称(比如HMAC-SHA256)组成;
Payload包含着关于用户数据的各种声明;
Signature就是密钥,用于验证消息在传递过程中有没有被更改,从而确保信息传输的安全。

JWT使用包的导入

  • github.com/dgrijalva/jwt-go
  • github.com/gin-gonic/gin

token的生成

type MyClaims struct {
   Username string `json:"username"`
   jwt.StandardClaims
}

const TokenExpireDuration = time.Hour * 2

var MySecret = []byte("MySecretKey")

func GenToken(username string) (string, error) {
   c := MyClaims{
      username,
      jwt.StandardClaims{
         ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(),
         Issuer:    "my-project",
      },
   }
   // 使用指定的签名方法(HS256)创建带有声明的新令牌。
   token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)

   // 使用秘密密钥签名令牌并获取编码后的字符串令牌。
   return token.SignedString(MySecret)
}

在上面的GenToken 函数中,将用户名作为参数传递,以生成一个包含指定声明的JWT。这个JWT可用于应用程序中的身份验证和授权,它将从生成时起的2小时内有效。下面是具体说明:
1.MyClaims 结构体

type MyClaims struct {
   Username string `json:"username"`
   jwt.StandardClaims
}
  • MyClaims是一个自定义结构体,用于定义将包含在JWT中的声明
  • 它嵌入了 jwt.StandardClaims 结构体,其中包含标准的JWT声明
  • Username 是一个自定义声明,将添加到JWT中,并使用 json:"username" 标签指定了如何将其编组为JSON

2.TokenExpireDuration 常量 const TokenExpireDuration = time.Hour * 2

  • 此常量定义了生成的JWT有效的持续时间。在这种情况下,它设置为2小时

3.MySecret
var MySecret = []byte("这是一段用于生成token的密钥")

  • MySecret 是一个包含秘密密钥的字节切片。该密钥将用于签名JWT,确保其真实性

4.GenToken 函数

func GenToken(username string) (string, error) {
   c := MyClaims{
      username,
      jwt.StandardClaims{
         ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(),
         Issuer:    "my-project",
      },
   }
   token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
   return token.SignedString(MySecret)
}
  • GenToken 是一个用于生成给定 username 的JWT的函数
  • 创建了一个新的 MyClaims 实例,其中包括提供的 username 并设置嵌入的 StandardClaims 中的 ExpiresAtIssuer 声明
  • 使用HS256签名方法创建一个新的JWT令牌(token),这是一种广泛使用的HMAC-SHA256签名方法
  • 使用 MySecret 密钥签名令牌,并将编码后的JWT作为字符串返回

token的解析与验证

// 解析JWT
func ParseToken(tokenString string) (*MyClaims, error) {
   // 解析token
   token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) {
      return MySecret, nil
   })
   if err != nil {
      return nil, err
   }
   if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
      return claims, nil
   }
   return nil, errors.New("invalid token")
}

这里的ParseToken 函数的主要用来解析JWT字符串并验证其有效性。如果JWT有效且声明与 MyClaims 类型兼容,它将返回JWT中包含的声明信息。否则,它将返回一个错误,指示JWT无效。这对于验证用户身份和授权非常有用,因为它可以从JWT中提取有关用户的信息。具体分析如下:

1.ParseToken函数

  • ParseToken 是一个函数,用于解析传入的JWT字符串 tokenString

2.jwt.ParseClaims

  • jwt.ParseWithClaims 函数是 github.com/dgrijalva/jwt-go 包提供的用于解析JWT的方法

  • 它接受三个参数:

    • tokenString:要解析的JWT字符串
    • &MyClaims{}:这是一个空的 MyClaims 结构体的实例,用于指定JWT中的声明类型。解析后的声明将被解码到这个结构体中
    • 一个函数:这个函数接受一个JWT令牌作为参数,并返回用于验证签名的密钥(在这里是 MySecret)和一个错误

3.解析JWT

  • jwt.ParseWithClaims 尝试解析传入的JWT字符串并验证签名
  • 如果解析过程中出现错误,它将返回一个错误对象
  • 如果JWT验证通过,它将返回一个 *jwt.Token 对象,其中包含了JWT的声明信息

4.检查声明

  • 接下来,代码检查JWT是否有效,并且声明是否与 MyClaims 类型兼容。
  • 如果JWT有效且声明与 MyClaims 类型兼容,它将返回声明(*MyClaims)和一个 nil 错误。
  • 如果JWT无效或声明不兼容,它将返回一个自定义错误,指示JWT无效。