在gin中使用JWT|青训营笔记

107 阅读4分钟

这是我参与「第五届青训营」伴学笔记创作活动的第10天

1. JWT的概念

JWT鉴权是指使用JWT(JSON Web Token)进行身份验证和授权的一种方式。JWT是一种轻量级的、开放标准的身份验证和授权协议,它将用户的身份信息编码为JSON格式的数据,并使用数字签名或加密的方式进行验证,从而保证数据的安全性。

在JWT鉴权中,当用户进行登录操作时,服务器会生成一个JWT,包含用户的身份信息和一些其他相关信息(如过期时间等),并将该JWT发送给客户端。客户端在随后的请求中,将该JWT作为请求的头部信息或请求参数发送给服务器。服务器在接收到请求后,会对JWT进行验证,并根据其中的身份信息进行身份认证和授权操作。

JWT具有以下几个特点:

  1. JWT是一种轻量级的身份验证和授权协议,不需要在服务器端存储会话信息,可以支持跨域访问,以及可以在多个应用之间共享身份验证信息等。

  2. JWT使用数字签名或加密的方式保证数据的安全性,防止被篡改或伪造。

  3. JWT具有一定的可扩展性,可以根据需要添加自定义的信息。

  4. JWT的缺点是一旦生成了JWT,其有效期就无法撤销或延长,因此需要设置合适的过期时间来保证安全性。。

JWT由三个部分组成:Header、Payload和Signature。Header部分包含JWT的类型和所使用的签名算法,Payload部分包含用户的身份信息以及其他相关信息,Signature部分是对Header和Payload进行数字签名的结果,用于验证JWT的完整性和真实性。

2. 使用JWT

golang中使用JWT有以下几个步骤

  1. 导入第三方库
import "github.com/dgrijalva/jwt-go"
  1. 签发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)  
}
  1. 解析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"`  
}
  1. Issuer(签发者):用于指定JWT的签发者。
  2. Subject(主题):用于指定JWT所面向的用户,也可以是用户的唯一标识。
  3. Audience(受众):用于指定JWT的接收方。
  4. ExpiresAt(过期时间):用于指定JWT的过期时间,必须是Unix时间戳。
  5. NotBefore(生效时间):用于指定JWT的生效时间,必须是Unix时间戳。
  6. IssuedAt(签发时间):用于指定JWT的签发时间,必须是Unix时间戳。
  7. 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错误

  1. 官方文档:jwt.io/introductio…
  2. 第三方库:github.com/dgrijalva/j…