/** * package utils * * JWT Token生成和验证工具包 * * 功能概述: * 1. 生成JWT Token(包含用户ID和过期时间) * 2. 解析JWT Token(验证签名和过期时间) * 3. 验证Token有效性(提取用户ID) * * 使用场景: * - 用户登录后生成Token * - API请求时验证Token * - 从Token中提取用户信息 */ package utils import ( "errors" "time" "github.com/golang-jwt/jwt/v5" "github.com/spf13/viper" ) // jwtSecret JWT签名密钥(从配置文件读取) var jwtSecret []byte /** * init * * 功能:初始化JWT签名密钥 * * 步骤: * 1. 从配置文件读取JWT密钥 * 2. 如果配置文件中没有,使用默认密钥(仅用于开发环境) * 3. 将密钥转换为字节数组存储 * * 注意:生产环境必须使用配置文件中的强随机密钥 */ func init() { secret := viper.GetString("jwt.secret") if secret == "" { secret = "xk-websocket-secret-key-2025" // 默认密钥,生产环境应使用配置 } jwtSecret = []byte(secret) } /** * Claims * * JWT Token的载荷结构 * * 字段说明: * - UserID: 用户ID(业务数据) * - RegisteredClaims: JWT标准声明(过期时间、签发时间等) */ type Claims struct { UserID string `json:"user_id"` // 用户ID jwt.RegisteredClaims // JWT标准声明 } /** * GenerateToken * * 功能:生成JWT Token * * 步骤: * 1. 设置Token过期时间(默认7天) * 2. 创建Claims对象,包含用户ID和标准声明 * 3. 使用HS256算法签名Token * 4. 返回Token字符串 * * @param userID 用户ID * @returns token字符串和错误 */ func GenerateToken(userID string) (string, error) { // 步骤1: 设置Token过期时间(7天后过期) expirationTime := time.Now().Add(7 * 24 * time.Hour) // 步骤2: 创建Claims对象,包含用户ID和标准声明 claims := &Claims{ UserID: userID, // 业务数据:用户ID RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(expirationTime), // 过期时间 IssuedAt: jwt.NewNumericDate(time.Now()), // 签发时间 NotBefore: jwt.NewNumericDate(time.Now()), // 生效时间(立即生效) }, } // 步骤3: 使用HS256算法创建Token并签名 token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) tokenString, err := token.SignedString(jwtSecret) if err != nil { return "", err } // 步骤4: 返回Token字符串 return tokenString, nil } /** * ParseToken * * 功能:解析JWT Token * * 步骤: * 1. 创建空的Claims对象 * 2. 使用密钥解析Token并验证签名 * 3. 检查Token是否有效(签名正确、未过期) * 4. 返回Claims对象 * * @param tokenString token字符串 * @returns Claims和错误 */ func ParseToken(tokenString string) (*Claims, error) { // 步骤1: 创建空的Claims对象 claims := &Claims{} // 步骤2: 解析Token并验证签名 // 使用密钥验证Token的签名是否有效 token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { return jwtSecret, nil // 返回签名密钥 }) if err != nil { return nil, err // 解析失败(签名错误、格式错误等) } // 步骤3: 检查Token是否有效(签名正确、未过期) if !token.Valid { return nil, errors.New("invalid token") } // 步骤4: 返回解析后的Claims对象 return claims, nil } /** * ValidateToken * * 功能:验证Token有效性并提取用户ID * * 步骤: * 1. 调用ParseToken解析Token * 2. 如果解析成功,从Claims中提取用户ID * 3. 返回用户ID * * 使用场景: * - 中间件中验证Token * - API处理器中获取当前用户ID * * @param tokenString token字符串 * @returns 用户ID和错误 */ func ValidateToken(tokenString string) (string, error) { // 步骤1: 解析Token claims, err := ParseToken(tokenString) if err != nil { return "", err // Token无效或已过期 } // 步骤2: 从Claims中提取用户ID return claims.UserID, nil }