136 lines
3.8 KiB
Go
136 lines
3.8 KiB
Go
package jwt
|
||
|
||
import (
|
||
"errors"
|
||
"time"
|
||
|
||
"github.com/golang-jwt/jwt/v5"
|
||
)
|
||
|
||
var (
|
||
ErrTokenExpired = errors.New("token已过期")
|
||
ErrTokenNotValidYet = errors.New("token尚未激活")
|
||
ErrTokenMalformed = errors.New("token格式错误")
|
||
ErrTokenInvalid = errors.New("无效的token")
|
||
)
|
||
|
||
// CustomClaims 自定义Claims
|
||
type CustomClaims struct {
|
||
BaseClaims
|
||
BufferTime int64 `json:"bufferTime"`
|
||
jwt.RegisteredClaims
|
||
}
|
||
|
||
// BaseClaims 基础Claims
|
||
type BaseClaims struct {
|
||
UUID string `json:"uuid"`
|
||
ID uint `json:"userId"`
|
||
Username string `json:"username"`
|
||
NickName string `json:"nickName"`
|
||
AuthorityID uint `json:"authorityId"`
|
||
}
|
||
|
||
// JWT JWT工具
|
||
type JWT struct {
|
||
SigningKey []byte
|
||
Issuer string
|
||
ExpiresAt time.Duration
|
||
BufferTime time.Duration
|
||
}
|
||
|
||
// NewJWT 创建JWT实例
|
||
func NewJWT(signingKey, issuer string, expiresAt, bufferTime time.Duration) *JWT {
|
||
return &JWT{
|
||
SigningKey: []byte(signingKey),
|
||
Issuer: issuer,
|
||
ExpiresAt: expiresAt,
|
||
BufferTime: bufferTime,
|
||
}
|
||
}
|
||
|
||
// CreateToken 创建token
|
||
func (j *JWT) CreateToken(baseClaims BaseClaims) (string, error) {
|
||
claims := CustomClaims{
|
||
BaseClaims: baseClaims,
|
||
BufferTime: int64(j.BufferTime / time.Second),
|
||
RegisteredClaims: jwt.RegisteredClaims{
|
||
Issuer: j.Issuer,
|
||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(j.ExpiresAt)),
|
||
NotBefore: jwt.NewNumericDate(time.Now().Add(-1000)),
|
||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||
},
|
||
}
|
||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||
return token.SignedString(j.SigningKey)
|
||
}
|
||
|
||
// CreateClaims 创建Claims
|
||
func (j *JWT) CreateClaims(baseClaims BaseClaims) CustomClaims {
|
||
return CustomClaims{
|
||
BaseClaims: baseClaims,
|
||
BufferTime: int64(j.BufferTime / time.Second),
|
||
RegisteredClaims: jwt.RegisteredClaims{
|
||
Issuer: j.Issuer,
|
||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(j.ExpiresAt)),
|
||
NotBefore: jwt.NewNumericDate(time.Now().Add(-1000)),
|
||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||
},
|
||
}
|
||
}
|
||
|
||
// ParseToken 解析token
|
||
func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) {
|
||
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||
return j.SigningKey, nil
|
||
})
|
||
if err != nil {
|
||
switch {
|
||
case errors.Is(err, jwt.ErrTokenExpired):
|
||
return nil, ErrTokenExpired
|
||
case errors.Is(err, jwt.ErrTokenMalformed):
|
||
return nil, ErrTokenMalformed
|
||
case errors.Is(err, jwt.ErrTokenNotValidYet):
|
||
return nil, ErrTokenNotValidYet
|
||
default:
|
||
return nil, ErrTokenInvalid
|
||
}
|
||
}
|
||
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
|
||
return claims, nil
|
||
}
|
||
return nil, ErrTokenInvalid
|
||
}
|
||
|
||
// NeedRefresh 判断是否需要刷新token
|
||
func (j *JWT) NeedRefresh(claims *CustomClaims) bool {
|
||
return claims.ExpiresAt.Unix()-time.Now().Unix() < claims.BufferTime
|
||
}
|
||
|
||
// CreateTokenByOldToken 根据旧token创建新token
|
||
func (j *JWT) CreateTokenByOldToken(oldToken string, oldClaims CustomClaims) (string, *CustomClaims, error) {
|
||
// 更新过期时间
|
||
oldClaims.ExpiresAt = jwt.NewNumericDate(time.Now().Add(j.ExpiresAt))
|
||
oldClaims.IssuedAt = jwt.NewNumericDate(time.Now())
|
||
oldClaims.NotBefore = jwt.NewNumericDate(time.Now().Add(-1000))
|
||
|
||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, oldClaims)
|
||
newToken, err := token.SignedString(j.SigningKey)
|
||
if err != nil {
|
||
return "", nil, err
|
||
}
|
||
return newToken, &oldClaims, nil
|
||
}
|
||
|
||
// NewJWTFromConfig 从配置创建JWT实例(内部使用)
|
||
func NewJWTFromConfig(signingKey, issuer, expiresTime, bufferTime string) *JWT {
|
||
expires, _ := time.ParseDuration(expiresTime)
|
||
if expires == 0 {
|
||
expires = 7 * 24 * time.Hour // 默认7天
|
||
}
|
||
buffer, _ := time.ParseDuration(bufferTime)
|
||
if buffer == 0 {
|
||
buffer = 24 * time.Hour // 默认1天
|
||
}
|
||
return NewJWT(signingKey, issuer, expires, buffer)
|
||
}
|