120 lines
3.0 KiB
Go
120 lines
3.0 KiB
Go
package jwt
|
||
|
||
import (
|
||
"errors"
|
||
"server/utility/ecode"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/golang-jwt/jwt/v5"
|
||
"github.com/google/uuid"
|
||
)
|
||
|
||
var (
|
||
// secretKey 是用于签名 JWT 的密钥。应替换为更加安全的密钥并妥善保管。
|
||
secretKey = []byte("1a40c1d5b7a1b0f0f835e0b24ca292a6")
|
||
|
||
// issuer 表示签发者信息,作为 JWT 标准字段的一部分。
|
||
issuer = "arenax.com"
|
||
)
|
||
|
||
type (
|
||
// TokenIn 表示生成 JWT 所需的输入参数。
|
||
//
|
||
// 字段:
|
||
// - UserId: 用户 ID;
|
||
// - Role: 权限标识;
|
||
// - ExpireTime: token 过期时间(可选)。
|
||
TokenIn struct {
|
||
UserId int64 // 用户 ID
|
||
Role string // 权限标识
|
||
ExpireTime time.Duration // 令牌有效期
|
||
}
|
||
|
||
// TokenOut 表示从 JWT 中解析出的用户信息。
|
||
//
|
||
// 字段:
|
||
// - UserId: 用户 ID;
|
||
// - Role: 权限标识;
|
||
// - JTI: JWT 的唯一标识。
|
||
TokenOut struct {
|
||
UserId int64 // 用户 ID
|
||
Role string // 权限标识
|
||
JTI string // JWT 唯一标识
|
||
}
|
||
|
||
// jwtClaims 自定义 JWT 的声明体结构,嵌入标准声明字段。
|
||
jwtClaims struct {
|
||
UserId int64 `json:"user_id"` // 用户 ID
|
||
Role string `json:"Role"` // 权限标识
|
||
JTI string `json:"jti"` // 唯一标识
|
||
jwt.RegisteredClaims
|
||
}
|
||
)
|
||
|
||
// GenerateToken 生成带有自定义权限和过期时间的 JWT 字符串。
|
||
//
|
||
// 参数:
|
||
// - in: 包含用户 ID、权限、过期时间等信息的 TokenIn 对象。
|
||
//
|
||
// 返回:
|
||
// - 生成的 JWT 字符串;
|
||
// - 若出错则返回错误信息。
|
||
func GenerateToken(in *TokenIn) (string, error) {
|
||
expire := in.ExpireTime
|
||
if expire <= 0 {
|
||
expire = 2 * time.Hour
|
||
}
|
||
|
||
claims := jwtClaims{
|
||
UserId: in.UserId,
|
||
Role: in.Role,
|
||
JTI: uuid.NewString(),
|
||
RegisteredClaims: jwt.RegisteredClaims{
|
||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expire)),
|
||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||
NotBefore: jwt.NewNumericDate(time.Now()),
|
||
Issuer: issuer,
|
||
},
|
||
}
|
||
|
||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||
return token.SignedString(secretKey)
|
||
}
|
||
|
||
// ParseToken 解析并验证 JWT 字符串并返回对应的用户信息。
|
||
// 自动去除开头的 "Bearer " 前缀。
|
||
//
|
||
// 参数:
|
||
// - tokenString: 需要解析的 JWT 字符串。
|
||
//
|
||
// 返回:
|
||
// - 解析后的 TokenOut 对象;
|
||
// - 若失败则返回相应的错误信息。
|
||
func ParseToken(tokenString string) (*TokenOut, error) {
|
||
if strings.HasPrefix(tokenString, "Bearer ") {
|
||
tokenString = strings.TrimPrefix(tokenString, "Bearer ")
|
||
}
|
||
|
||
token, err := jwt.ParseWithClaims(tokenString, &jwtClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||
return secretKey, nil
|
||
})
|
||
if err != nil {
|
||
if errors.Is(err, jwt.ErrTokenExpired) {
|
||
return nil, ecode.Expire.Sub("token 已过期")
|
||
}
|
||
return nil, ecode.Fail.Sub("解析 token 出现异常")
|
||
}
|
||
|
||
claims, ok := token.Claims.(*jwtClaims)
|
||
if !ok || !token.Valid {
|
||
return nil, ecode.InvalidOperation.Sub("无效的 Token")
|
||
}
|
||
|
||
return &TokenOut{
|
||
UserId: claims.UserId,
|
||
Role: claims.Role,
|
||
JTI: claims.JTI,
|
||
}, nil
|
||
}
|