JWT,全称 JSON Web Token,是一种开放标准(RFC 7519),用于安全地在双方之间传递信息。尤其适用于身份验证和授权场景。JWT 的设计允许信息在各方之间安全地、 compactly(紧凑地)传输,因为其自身包含了所有需要的认证信息,从而减少了需要查询数据库或会话存储的需求。
安装
go get -u github.com/dgrijalva/jwt-go
定义配置项
type Jwt struct {
Secret string `mapstructure:"secret" json:"secret" yaml:"secret"`
JwtTtl int64 `mapstructure:"jwt_ttl" json:"jwt_ttl" yaml:"jwt_ttl"` // token 有效期(秒)
}
config.yaml
jwt:
secret: 3Bde3BGEbYqtqyEUzW3ry8jKFcaPH17fRmTmqE7MDr05Lwj95uruRKrrkb44TJ4s
jwt_ttl: 43200
编写颁发 Token 逻辑
services/jwt.go
package services
import (
"errors"
"leo-gin/config"
"time"
"github.com/dgrijalva/jwt-go"
)
type jwtService struct {
}
var JwtService = new(jwtService)
// CustomClaims 自定义 Claims
type CustomClaims struct {
jwt.StandardClaims
}
type TokenOutPut struct {
AccessToken string `json:"access_token"`
ExpiresIn int `json:"expires_in"`
}
// CreateToken 生成 Token
func (jwtService *jwtService) CreateToken(userId string) (tokenData TokenOutPut, token *jwt.Token, err error) {
token = jwt.NewWithClaims(
jwt.SigningMethodHS256,
CustomClaims{
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Unix() + config.Conf.Jwt.JwtTtl,
Id: userId,
Issuer: config.Conf.Jwt.GuardName, // 用于在中间件中区分不同客户端颁发的 token,避免 token 跨端使用
NotBefore: time.Now().Unix() - 1000,
},
},
)
tokenStr, err := token.SignedString([]byte(config.Conf.Jwt.Secret))
tokenData = TokenOutPut{
tokenStr,
int(config.Conf.Jwt.JwtTtl),
}
return
}
// 解析 Token 的方法
func ParseToken(tokenStr string) (*CustomClaims, error) {
token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(config.Conf.Jwt.Secret), nil
})
if err != nil {
return nil, err
}
// 校验是否是合法的 Claims
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
return claims, nil
}
return nil, errors.New("invalid token")
}
// 验证 Token 的方法
func VerifyToken(tokenStr string) int {
claims, err := ParseToken(tokenStr)
if err != nil {
return 1
}
if time.Now().Unix() > claims.ExpiresAt-10 {
return 2
}
return 0
}
生成Token
loginReq.User = req
tokenData, _, err := services.JwtService.CreateToken("userId1233456")
if err != nil {
c.JSON(http.StatusBadRequest, SetOut(400, nil, err.Error()))
return
}
loginReq.Token = tokenData.AccessToken
loginReq.ExpiresIn = tokenData.ExpiresIn
c.JSON(http.StatusOK, SetOut(200, loginReq))
验证Token中间件
// authRouter := Router.Group("auth", AuthMiddleware())
// 认证中间件
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
tokenInt := services.VerifyToken(token)
if tokenInt == 1 {
c.JSON(http.StatusUnauthorized, controllers.SetOut(401, "Unauthorized"))
c.Abort()
return
} else if tokenInt == 2 {
c.JSON(http.StatusForbidden, controllers.SetOut(403, "Token expiration"))
c.Abort()
return
}
c.Next()
}
}