写在前面
项目的具体开发,总是会有许许多多的问题暴露出来。但是路还是要一步一步走,今天来学习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-gogithub.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中的ExpiresAt和Issuer声明 - 使用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无效。