package auth import ( "fmt" "time" "github.com/golang-jwt/jwt/v5" "photography-backend/internal/config" ) // JWTService JWT服务 type JWTService struct { secretKey []byte accessTokenDuration time.Duration refreshTokenDuration time.Duration } // JWTClaims JWT声明 type JWTClaims struct { UserID uint `json:"user_id"` Username string `json:"username"` Role string `json:"role"` jwt.RegisteredClaims } // TokenPair 令牌对 type TokenPair struct { AccessToken string `json:"access_token"` RefreshToken string `json:"refresh_token"` TokenType string `json:"token_type"` ExpiresIn int64 `json:"expires_in"` } // NewJWTService 创建JWT服务 func NewJWTService(cfg *config.JWTConfig) *JWTService { accessDuration, _ := time.ParseDuration(cfg.ExpiresIn) refreshDuration, _ := time.ParseDuration(cfg.RefreshExpiresIn) return &JWTService{ secretKey: []byte(cfg.Secret), accessTokenDuration: accessDuration, refreshTokenDuration: refreshDuration, } } // GenerateTokenPair 生成令牌对 func (s *JWTService) GenerateTokenPair(userID uint, username, role string) (*TokenPair, error) { // 生成访问令牌 accessToken, err := s.generateToken(userID, username, role, s.accessTokenDuration) if err != nil { return nil, fmt.Errorf("failed to generate access token: %w", err) } // 生成刷新令牌 refreshToken, err := s.generateToken(userID, username, role, s.refreshTokenDuration) if err != nil { return nil, fmt.Errorf("failed to generate refresh token: %w", err) } return &TokenPair{ AccessToken: accessToken, RefreshToken: refreshToken, TokenType: "Bearer", ExpiresIn: int64(s.accessTokenDuration.Seconds()), }, nil } // generateToken 生成令牌 func (s *JWTService) generateToken(userID uint, username, role string, duration time.Duration) (string, error) { now := time.Now() claims := &JWTClaims{ UserID: userID, Username: username, Role: role, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(now.Add(duration)), IssuedAt: jwt.NewNumericDate(now), NotBefore: jwt.NewNumericDate(now), Issuer: "photography-backend", }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(s.secretKey) } // ValidateToken 验证令牌 func (s *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, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } return s.secretKey, nil }) if err != nil { return nil, fmt.Errorf("failed to parse token: %w", err) } if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid { return claims, nil } return nil, fmt.Errorf("invalid token") } // RefreshToken 刷新令牌 func (s *JWTService) RefreshToken(refreshToken string) (*TokenPair, error) { claims, err := s.ValidateToken(refreshToken) if err != nil { return nil, fmt.Errorf("invalid refresh token: %w", err) } // 生成新的令牌对 return s.GenerateTokenPair(claims.UserID, claims.Username, claims.Role) } // GetClaimsFromToken 从令牌中获取声明 func (s *JWTService) GetClaimsFromToken(tokenString string) (*JWTClaims, error) { token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) { return s.secretKey, nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*JWTClaims); ok { return claims, nil } return nil, fmt.Errorf("invalid claims") }