kra/pkg/jwt/jwt.go

123 lines
3.3 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
}