这是我参与「第五届青训营」伴学笔记创作活动的第10天
1. JWT的概念
JWT鉴权是指使用JWT(JSON Web Token)进行身份验证和授权的一种方式。JWT是一种轻量级的、开放标准的身份验证和授权协议,它将用户的身份信息编码为JSON格式的数据,并使用数字签名或加密的方式进行验证,从而保证数据的安全性。
在JWT鉴权中,当用户进行登录操作时,服务器会生成一个JWT,包含用户的身份信息和一些其他相关信息(如过期时间等),并将该JWT发送给客户端。客户端在随后的请求中,将该JWT作为请求的头部信息或请求参数发送给服务器。服务器在接收到请求后,会对JWT进行验证,并根据其中的身份信息进行身份认证和授权操作。
JWT具有以下几个特点:
-
JWT是一种轻量级的身份验证和授权协议,不需要在服务器端存储会话信息,可以支持跨域访问,以及可以在多个应用之间共享身份验证信息等。
-
JWT使用数字签名或加密的方式保证数据的安全性,防止被篡改或伪造。
-
JWT具有一定的可扩展性,可以根据需要添加自定义的信息。
-
JWT的缺点是一旦生成了JWT,其有效期就无法撤销或延长,因此需要设置合适的过期时间来保证安全性。。
JWT由三个部分组成:Header、Payload和Signature。Header部分包含JWT的类型和所使用的签名算法,Payload部分包含用户的身份信息以及其他相关信息,Signature部分是对Header和Payload进行数字签名的结果,用于验证JWT的完整性和真实性。
2. 使用JWT
golang中使用JWT有以下几个步骤
- 导入第三方库
import "github.com/dgrijalva/jwt-go"
- 签发JWT
type MyClaims struct {
UserName string
jwt.StandardClaims // 第三方库的标准claims实现
}
func creatJWT(str string) (string, error) {
// 创建声明
myClaims := MyClaims{
UserName: str,
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Unix() + 2,
NotBefore: time.Now().Unix(),
},
}
// 创建token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, myClaims)
// 对token进行签名
return token.SignedString(jwtKey)
}
- 解析JWT
func parseJWT(str string) *MyClaims {
token, err := jwt.ParseWithClaims(str, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
return jwtKey, nil
})
if err != nil {
fmt.Println(err)
}
name := token.Claims.(*MyClaims).UserName
fmt.Println(name)
fmt.Println(token.Valid)
return token.Claims.(*MyClaims)
}
StandardClaims是JWT提供的标准声明模型
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"`
}
Issuer(签发者):用于指定JWT的签发者。Subject(主题):用于指定JWT所面向的用户,也可以是用户的唯一标识。Audience(受众):用于指定JWT的接收方。ExpiresAt(过期时间):用于指定JWT的过期时间,必须是Unix时间戳。NotBefore(生效时间):用于指定JWT的生效时间,必须是Unix时间戳。IssuedAt(签发时间):用于指定JWT的签发时间,必须是Unix时间戳。ID(唯一标识):用于指定JWT的唯一标识符。
3. 在gin中使用JWT
在gin框架中,通常会使用中间件来实现JWT认证和授权。以下是一个示例,用于验证请求头中的Authorization字段中是否包含有效的JWT
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.AbortWithStatusJSON(401, gin.H{"error": "Authorization header required"})
return
}
token, err := jwt.Parse(authHeader, func(token *jwt.Token) (interface{}, error) {
// 这里的key应该从环境变量或者配置文件中获取
key := []byte("my_secret_key")
return key, nil
})
if err != nil {
c.AbortWithStatusJSON(401, gin.H{"error": "Invalid token"})
return
}
if !token.Valid {
c.AbortWithStatusJSON(401, gin.H{"error": "Invalid token"})
return
}
c.Next()
}
}
在需要进行认证和授权的路由上,可以使用上面定义的中间件进行验证
r := gin.Default()
r.GET("/api/user/:id", AuthMiddleware(), func(c *gin.Context) {
id := c.Param("id")
// 验证通过,获取用户信息并返回
c.JSON(200, gin.H{"id": id, "name": "Alice", "age": 18})
})
当访问/api/user/:id时,需要进行JWT认证和授权。在路由的处理函数中,我们可以通过解析URL参数和JWT中包含的信息,获取用户信息并返回。如果JWT验证失败,中间件会返回401 Unauthorized错误
- 官方文档:jwt.io/introductio…
- 第三方库:github.com/dgrijalva/j…