package jwt import ( "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; // - Permission: 权限标识; // - ExpireTime: token 过期时间(可选)。 TokenIn struct { UserId int // 用户 ID Permission string // 权限标识 ExpireTime time.Duration // 令牌有效期 } // TokenOut 表示从 JWT 中解析出的用户信息。 // // 字段: // - UserId: 用户 ID; // - Permission: 权限标识; // - JTI: JWT 的唯一标识。 TokenOut struct { UserId int // 用户 ID Permission string // 权限标识 JTI string // JWT 唯一标识 } // jwtClaims 自定义 JWT 的声明体结构,嵌入标准声明字段。 jwtClaims struct { UserId int `json:"user_id"` // 用户 ID Permission string `json:"permission"` // 权限标识 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, Permission: in.Permission, 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 { 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, Permission: claims.Permission, JTI: claims.JTI, }, nil }