依赖安装
go get -u github.com/golang-jwt/jwt/v5
文档地址
创建对象
jwt的相关配置
# jwt configuration
jwt:
signing-key: xxx
expires-time: 7d
buffer-time: 1d
issuer: fancy_fish
claim-strings: fancy_fish_to_do_list
claims类型配置
package request
import (
"github.com/golang-jwt/jwt/v5"
"github.com/google/uuid"
)
type BaseClaims struct {
UUID uuid.UUID
Username string
jwt.RegisteredClaims
}
type CustomClaims struct {
BaseClaims
BufferTime int64
jwt.RegisteredClaims
}
代码示例
package util
import (
"ToDoList/enum"
"ToDoList/global"
"ToDoList/model/request"
"fmt"
"github.com/gin-gonic/gin"
jwt "github.com/golang-jwt/jwt/v5"
"net"
"time"
)
type _jwt struct {
SigningKey []byte
Claims jwt.Claims
}
// 解析token 验证是否有效
func (receiver *_jwt) ValidateToken(tokenString string) (*request.CustomClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) {
return receiver.SigningKey, nil
})
if err != nil {
fmt.Println(err, "token验证错误")
return nil, err
}
if token != nil {
if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid {
return claims, nil
}
return nil, enum.TokenInvalid
} else {
return nil, enum.TokenInvalid
}
}
func (receiver *_jwt) CreateToken(claims request.CustomClaims) (string, error) {
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := t.SignedString(receiver.SigningKey)
if err != nil {
fmt.Println("toen生成失败")
return token, err
}
return token, nil
}
// 创建生成token必须的clasims
func (receiver *_jwt) CreateClaims(baseClaims request.BaseClaims) request.CustomClaims {
// 按天解析,time.ParseDuration()不支持按天。
bft, _ := BasicUtils.ParseDuration(global.GVA_CONFIG.JWT.BufferTime)
ept, _ := BasicUtils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime)
claims := request.CustomClaims{
BaseClaims: baseClaims,
BufferTime: int64(bft / time.Second), // 缓冲时间1天 缓冲时间内会获得新的token刷新令牌 此时一个用户会存在两个有效令牌 但是前端只留一个 另一个会丢失
RegisteredClaims: jwt.RegisteredClaims{
Audience: jwt.ClaimStrings{global.GVA_CONFIG.JWT.ClaimStrings}, // 受众
NotBefore: jwt.NewNumericDate(time.Now().Add(-1000)), // 签名生效时间
ExpiresAt: jwt.NewNumericDate(time.Now().Add(ept)), // 过期时间 7天 配置文件
Issuer: global.GVA_CONFIG.JWT.Issuer, // 签名的发行者
},
}
return claims
}
func JWTNew() *_jwt {
return &_jwt{
SigningKey: []byte(global.GVA_CONFIG.JWT.SigningKey),
}
}
var JWTToken = JWTNew()
func SetToken(c *gin.Context, token string, maxAge int) {
// 增加cookie x-token 向来源的web添加
host, _, err := net.SplitHostPort(c.Request.Host)
if err != nil {
host = c.Request.Host
}
if net.ParseIP(host) != nil {
c.SetCookie("x-token", token, maxAge, "/", "", false, false)
} else {
c.SetCookie("x-token", token, maxAge, "/", host, false, false)
}
}
func GetToken(c *gin.Context) string {
token, _ := c.Cookie("x-token")
if token == "" {
token = c.Request.Header.Get("x-token")
}
return token
}
按天解析时间
func (receiver basicUtils) ParseDuration(d string) (time.Duration, error) {
d = strings.TrimSpace(d)
dr, err := time.ParseDuration(d)
if err == nil {
return dr, nil
}
if strings.Contains(d, "d") {
index := strings.Index(d, "d")
hour, _ := strconv.Atoi(d[:index])
dr = time.Hour * 24 * time.Duration(hour)
ndr, err := time.ParseDuration(d[index+1:])
if err != nil {
return dr, nil
}
return dr + ndr, nil
}
dv, err := strconv.ParseInt(d, 10, 64)
return time.Duration(dv), err
}
生成token
j := util.JWTNew()
claims := j.CreateClaims(request.BaseClaims{
UUID: u.UUID,
Username: u.Username,
})
token, err := j.CreateToken(claims)
总结
Token的组成成分
- 秘钥这个自定义一个字符串即可
- 声明名称的列表可以将用户名或 ID 或角色编码到令牌中,也可以称为载荷
- 签名算法
关键函数的签名
func NewWithClaims(method SigningMethod, claims Claims, opts ...TokenOption) *Token
JWT-GO使用主要有以下步骤
- 配置私钥
NewWithClaims
传入方法和声明- 通过
SignedString
创建token ParseWithClaims
传入token解析token