package auth import ( "errors" "time" "github.com/golang-jwt/jwt/v5" ) // JWTClaims JWT声明 type JWTClaims struct { UserID uint `json:"user_id"` Roles []string `json:"roles"` jwt.RegisteredClaims } // JWTService JWT服务 type JWTService struct { secretKey string expire int // 过期时间(秒) } // NewJWTService 创建JWT服务 func NewJWTService(secretKey string, expire int) *JWTService { return &JWTService{ secretKey: secretKey, expire: expire, } } // GenerateToken 生成JWT令牌 func (j *JWTService) GenerateToken(userID uint, roles []string) (string, error) { // 创建声明 claims := JWTClaims{ UserID: userID, Roles: roles, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(j.expire) * time.Second)), IssuedAt: jwt.NewNumericDate(time.Now()), NotBefore: jwt.NewNumericDate(time.Now()), Issuer: "web-training", Subject: "user-auth", }, } // 创建令牌 token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) // 签名令牌 tokenString, err := token.SignedString([]byte(j.secretKey)) if err != nil { return "", err } return tokenString, nil } // ValidateToken 验证JWT令牌 func (j *JWTService) ValidateToken(tokenString string) (*JWTClaims, error) { // 解析令牌 token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) { // 验证签名方法 if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, errors.New("unexpected signing method") } return []byte(j.secretKey), nil }) if err != nil { return nil, err } // 验证令牌有效性 if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid { return claims, nil } return nil, errors.New("invalid token") } // RefreshToken 刷新JWT令牌 func (j *JWTService) RefreshToken(tokenString string) (string, error) { // 验证旧令牌 claims, err := j.ValidateToken(tokenString) if err != nil { return "", err } // 生成新令牌 return j.GenerateToken(claims.UserID, claims.Roles) } // ExtractTokenFromHeader 从请求头提取令牌 func ExtractTokenFromHeader(authHeader string) (string, error) { if authHeader == "" { return "", errors.New("authorization header is empty") } parts := strings.Split(authHeader, " ") if len(parts) != 2 || parts[0] != "Bearer" { return "", errors.New("authorization header format must be Bearer {token}") } return parts[1], nil }