文章目录
- 简介
- 引入
- 源码
- 代码模型
- router 中写法
- middlerware 中写法
- ParseToken 解析 token string => *jwt.Token
- secretKey 密钥
- AuthClaims 结构体
- GenerateToken 生成 *jwt.Token
- login 登录后响应头设置 COOKIE
- 常规 HandlerFunc 使用用户信息
简介
目前主流的 gin 的鉴权框架有 github 上的 dgrijalva/jwt-go 和 golang-jwt/jwt,但是 dgrijalva/jwt-go 以前用的特别多,但是有一些漏洞,现在更推荐的是 golang-jwt/jwt 官方社区版
github:https://github.com/golang-jwt/jwt
官网:https://pkg.go.dev/github.com/golang-jwt/jwt/v4
JWT(JSON Web Tokens),
引入
go get -u github.com/golang-jwt/jwt
import "github.com/golang-jwt/jwt"
源码
type Token struct {Raw string Method SigningMethod Header map[string]interface{} Claims Claims Signature string Valid bool
}
JWT 中的 token如上图,完整的 token 分为 3 部分
- The first segment of the token:Header
- The second segment of the token:Claims
- The third segment of the token. Populated when you Parse a token:Signature
代码模型
- 登录的 HandlerFunc 中,需要生成 token,并设置响应头带上这个 token
- 中间件可以处理分组的请求,检测 Authorization 中数据做解析判定数据是否有效,如果无效直接返回无权限,不会进入到具体 HandlerFunc 中操作,如果有效则把 claims 中的用户信息保存到 gin.context 中,然后放行进入 HandlerFunc 中
router 中写法
r := gin.Default()authGroup := r.Group("/auth")
authGroup.Use(middleware.JWTAuth())
middlerware 中写法
中间件中做到解析 token,然后把 token 中的用户信息存放在 gin.Context 中,方便后面 HandlerFunc 中取用
func JWTAuth() gin.HandlerFunc {return func(c *gin.Context) {tokenStr := c.GetHeader("Authorization")if tokenStr == "" {c.JSON(http.StatusForbidden, "No token. You don't have permission!")c.Abort()return}token, err := ParseToken(tokenStr)if err != nil {c.JSON(http.StatusForbidden, "Invalid token! You don't have permission!")c.Abort()return}claims, ok := token.Claims.(*AuthClaims)if !ok {c.JSON(http.StatusForbidden, "Invalid token!")c.Abort()return}c.Set("userId", claims.UserId)c.Next()}
}
ParseToken 解析 token string => *jwt.Token
func ParseToken(tokenStr string) (*jwt.Token, error) {return jwt.ParseWithClaims(tokenStr, &AuthClaims{}, func(tk *jwt.Token) (interface{}, error) {return secretKey, nil})
}
secretKey 密钥
建议不要存放在项目代码中,要单独私有存放
var secretKey = []byte("some string")
AuthClaims 结构体
type AuthClaims struct {UserId uint64 `json:"userId"`jwt.StandardClaims
}
GenerateToken 生成 *jwt.Token
一般在 login 后来生成 *jwt.Token 存放在响应头中给浏览器
func GenerateToken(userId uint64, expireTime time.Time) (string, error) {claim := AuthClaims{UserId: userId,StandardClaims: jwt.StandardClaims{ExpiresAt: expireTime.Unix(),IssuedAt: time.Now().Unix(),Issuer: "abcnull",Subject: "gindemo",},}noSignedToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claim)return noSignedToken.SignedString(secretKey)
}
login 登录后响应头设置 COOKIE
login 登录之后需要把 token string 带到响应头中返回给前端浏览器来保存信息
userId := 1
var expireTime = time.Now().Add(60 * 24 * time.Hour)
tokenStr, tokenErr := middleware.GenerateToken(userId, expireTime)
if tokenErr != nil {
}
c.SetCOOKIE("Authorization", tokenStr, 60, "/", "127.0.0.1", false, true)
常规 HandlerFunc 使用用户信息
userId, flag := c.Get("userId")