kra/pkg/jwt/jwt.go

136 lines
3.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}