# Sub2API 模块分析报告:认证与授权模块 ## 1. 模块概述 ### 1.1 模块定位 认证与授权模块是 Sub2API 的安全核心,负责验证用户身份、管理 API Key、配置访问权限。该模块确保只有授权用户才能访问系统资源,并实施精细的访问控制策略。 ### 1.2 核心职责 - **用户认证**:支持密码登录、OAuth 第三方登录、JWT Token 认证 - **API Key 管理**:创建、验证、吊销 API Key - **权限控制**:基于角色和分组的访问控制 - **二次验证**:TOTP 双因素认证支持 ## 2. 代码结构分析 ### 2.1 核心文件 | 文件路径 | 职责 | 代码行数 | |---------|------|----------| | `middleware/jwt_auth.go` | JWT Token 认证中间件 | ~300 行 | | `middleware/api_key_auth.go` | API Key 认证中间件 | ~250 行 | | `middleware/admin_auth.go` | 管理员权限验证 | ~150 行 | | `service/auth_service.go` | 认证核心服务 | ~900 行 | | `service/api_key_service.go` | API Key 服务 | ~900 行 | | `service/totp_service.go` | TOTP 双因素认证 | ~400 行 | | `handler/auth_handler.go` | 认证 API 处理器 | ~300 行 | | `handler/api_key_handler.go` | API Key API 处理器 | ~300 行 | ### 2.2 目录结构 ``` backend/internal/ ├── server/middleware/ │ ├── jwt_auth.go # JWT 认证 │ ├── api_key_auth.go # API Key 认证 │ ├── admin_auth.go # 管理员认证 │ └── auth_subject.go # 认证主体解析 └── service/ ├── auth_service.go # 认证服务 ├── api_key_service.go # API Key 服务 └── totp_service.go # TOTP 服务 ``` ## 3. 功能详细分析 ### 3.1 认证机制 #### 3.1.1 JWT Token 认证 **流程:** ``` 用户登录 → 验证密码 → 生成 JWT Token → 返回给客户端 后续请求 → 验证 JWT → 解析用户信息 → 授权访问 ``` **实现代码:** (`middleware/jwt_auth.go`) ```go func NewJWTAuthMiddleware(cfg *config.Config) gin.HandlerFunc { return func(c *gin.Context) { // 1. 从 Header 获取 Token token := extractToken(c) // 2. 解析 Token claims, err := jwtUtils.ParseToken(token, cfg.JWT.Secret) if err != nil { c.AbortWithStatusJSON(401, gin.H{"error": "invalid token"}) return } // 3. 设置用户上下文 c.Set("user_id", claims.UserID) c.Set("role", claims.Role) c.Next() } } ``` **配置参数:** - Token 有效期:24 小时(可配置) - 签名算法:HS256/HS384/HS512 - 刷新机制:支持 Refresh Token #### 3.1.2 API Key 认证 **特点:** - 永久有效(除非被吊销) - 绑定用户和分组 - 支持 IP 白名单 - 支持速率限制 **验证流程:** ```go // service/api_key_service.go - ValidateKey func (s *APIKeyService) ValidateKey(ctx context.Context, key string) (*APIKey, *User, error) { // 1. 缓存查询(两级:L1 内存 + L2 Redis) if cached := s.getAuthCache(key); cached != nil { return cached.APIKey, cached.User, nil } // 2. 数据库查询 apiKey, err := s.apiKeyRepo.GetByKey(ctx, key) if err != nil { return nil, nil, ErrInvalidAPIKey } // 3. 状态检查 if apiKey.Status != StatusActive { return nil, nil, ErrAPIKeyDisabled } // 4. IP 白名单检查 if !s.checkIPWhitelist(c, apiKey) { return nil, nil, ErrIPNotAllowed } return apiKey, user, nil } ``` #### 3.1.3 OAuth 第三方登录 **支持的提供商:** - **Anthropic OAuth**:Claude 账号授权 - **Google OAuth**:Gemini 账号授权 - **OpenAI OAuth**:OpenAI 账号授权 - **Linux.do OAuth**:社区账号登录 **实现结构:** ```go // service/oauth_service.go type OAuthProvider interface { GetAuthURL() string ExchangeCode(token string) (*OAuthToken, error) RefreshToken(token string) (*OAuthToken, error) } ``` ### 3.2 授权控制 #### 3.2.1 基于角色的访问控制 (RBAC) **角色层级:** ```go const ( RoleUser Role = "user" // 普通用户 RoleAdmin Role = "admin" // 管理员 RoleSuperAdmin Role = "super_admin" // 超级管理员 ) ``` **权限检查:** ```go // middleware/admin_only.go func AdminOnly() gin.HandlerFunc { return func(c *gin.Context) { role, exists := c.Get("role") if !exists || role != RoleAdmin { c.AbortWithStatusJSON(403, gin.H{"error": "admin access required"}) return } c.Next() } } ``` #### 3.2.2 分组级别的访问控制 ```go // API Key 绑定到分组 type APIKey struct { GroupID *int64 // 所属分组 // 用户只能访问自己分组内的资源 } ``` ### 3.3 API Key 管理 #### 3.3.1 创建 API Key ```go // service/api_key_service.go - Create func (s *APIKeyService) Create(ctx context.Context, userID int64, req CreateAPIKeyRequest) (*APIKey, error) { // 1. 生成 Key 值 key := "sk-" + generateRandomKey(32) // 2. 设置默认值 apiKey := &APIKey{ Key: key, UserID: userID, Status: StatusActive, Quota: req.Quota, // IP 白名单、速率限制等 } // 3. 存储到数据库 return s.apiKeyRepo.Create(ctx, apiKey) } ``` **Key 格式:** `sk-{随机32位字符}` #### 3.3.2 缓存策略 **两级缓存架构:** ``` ┌─────────────────────────────────────┐ │ L1 Cache (内存) │ │ - 容量:10000 条 │ │ - TTL:1 分钟 │ │ - 命中率:~90% │ └─────────────────────────────────────┘ ↑ │ 缓存未命中 ▼ ┌─────────────────────────────────────┐ │ L2 Cache (Redis) │ │ - 容量:无限制 │ │ - TTL:5 分钟 │ └─────────────────────────────────────┘ ↑ │ 缓存未命中 ▼ ┌─────────────────────────────────────┐ │ Database (PostgreSQL) │ │ - 查询延迟:~10ms │ └─────────────────────────────────────┘ ``` ### 3.4 双因素认证 (TOTP) #### 3.4.1 启用流程 ```go // service/totp_service.go - EnableTOTP func (s *TOTPService) EnableTOTP(ctx context.Context, userID int64) (*TOTPSetup, error) { // 1. 生成密钥 secret := generateTOTPSecret() // 2. 生成 QR 码(用户扫描到 authenticator app) qrCode := generateQRCode(secret, user.Email) // 3. 临时存储密钥(未验证前不生效) s.tempStore.Set(userID, secret) return &TOTPSetup{ Secret: secret, QRCode: qrCode, }, nil } ``` #### 3.4.2 验证流程 ```go // service/totp_service.go - VerifyTOTP func (s *TOTPService) VerifyTOTP(ctx context.Context, userID int64, code string) error { // 1. 获取用户密钥 secret := s.getUserSecret(userID) // 2. 验证 TOTP 码(支持 30s 窗口) valid := totp.Validate(code, secret) if !valid { return ErrInvalidTOTP } // 3. 标记为已启用 s.markAsEnabled(userID) return nil } ``` **安全特性:** - 密钥加密存储(AES-256) - 支持时间窗口(前一个、后一个码可用) - 错误锁定(连续 5 次错误锁定 30 分钟) ## 4. 安全加固 ### 4.1 密码安全 ```go // service/auth_service.go func (s *AuthService) HashPassword(password string) string { // 使用 bcrypt,cost = 12 hash, _ := bcrypt.GenerateFromPassword([]byte(password), 12) return string(hash) } func (s *AuthService) VerifyPassword(password, hash string) bool { err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) return err == nil } ``` **配置参数:** - Bcrypt cost:12(可配置 10-15) - 密码最小长度:8 字符 - 密码复杂度:无强制要求(建议启用) ### 4.2 速率限制 ```go // middleware/rate_limiter.go func NewRateLimiter() gin.HandlerFunc { return func(c *gin.Context) { key := getRateLimitKey(c) // 基于 Token Bucket 算法 if !allowRequest(key) { c.AbortWithStatusJSON(429, gin.H{ "error": "rate limit exceeded", "retry_after": getRetryAfter(key), }) return } c.Next() } } ``` **限制级别:** | 级别 | 限制 | 说明 | |------|------|------| | 用户 | 1000 RPM | 每用户请求速率 | | API Key | 500 RPM | 每 Key 请求速率 | | IP | 2000 RPM | 每 IP 请求速率 | ### 4.3 审计日志 ```go // 记录所有认证事件 func logAuthEvent(event AuthEvent) { logger.Info("auth_event", "user_id", event.UserID, "action", event.Action, "ip", event.IP, "success", event.Success, "timestamp", event.Timestamp, ) } // 事件类型: // - login_success / login_failed // - logout // - api_key_created / api_key_revoked // - totp_enabled / totp_disabled // - password_changed ``` ## 5. 配置参数 ### 5.1 认证配置(config.yaml) ```yaml jwt: secret: "your-256-bit-secret" expire_hour: 24 refresh_expire_hour: 168 # 7 天 api_key: # API Key 缓存配置 cache: l1_size: 10000 l1_ttl: 1m l2_ttl: 5m rate_limit: user_rpm: 1000 apikey_rpm: 500 ip_rpm: 2000 totp: issuer: "Sub2API" enabled: true ``` ### 5.2 环境变量 | 变量 | 说明 | 默认值 | |------|------|--------| | `JWT_SECRET` | JWT 签名密钥 | 必需 | | `TOTP_ENCRYPTION_KEY` | TOTP 密钥加密密钥 | 必需 | | `RATE_LIMIT_ENABLED` | 启用速率限制 | true | | `TOTP_ENABLED` | 启用 TOTP | true | ## 6. 集成与扩展 ### 6.1 外部系统集成 **管理员 API Key:** ```go // 用于外部系统(如支付系统)调用 Admin API type AdminAPIKey struct { Key: string // 格式:admin-<64位hex> Role: string // admin 或 super_admin } ``` **使用方式:** ```bash curl -H "x-api-key: admin-xxxxxxxxxxxxxx" \ https://your-domain/api/v1/admin/users ``` ### 6.2 自定义认证提供者 要添加新的认证方式,需要: 1. **实现认证接口** ```go type AuthProvider interface { Authenticate(credentials) (*User, error) Refresh(token) (*User, error) } ``` 2. **注册到路由器** ```go // server/routes/auth.go router.POST("/auth/custom", customAuthHandler) ``` ## 7. 修改和扩展指南 ### 7.1 常见修改场景 **场景 1:调整 API Key 缓存策略** 修改文件:`service/api_key_auth_cache_impl.go` ```go func (s *APIKeyService) getAuthCache(key string) (*APIKeyAuthCacheEntry, bool) { // 调整 L1 缓存大小 l1Size := 20000 // 从 10000 增加到 20000 // 调整 L1 TTL l1TTL := 2 * time.Minute // 从 1 分钟增加到 2 分钟 } ``` **场景 2:添加新的 OAuth 提供商** 1. 在 `service/oauth/` 目录创建新服务 2. 实现 `OAuthProvider` 接口 3. 在 `auth_service.go` 注册 **场景 3:调整速率限制** 修改文件:`middleware/rate_limiter.go` ```go const ( UserRPM = 2000 // 从 1000 增加到 2000 APIKeyRPM = 1000 // 从 500 增加到 1000 ) ``` ### 7.2 安全注意事项 1. **JWT Secret 必须足够复杂**:至少 256 位随机字符串 2. **TOTP 密钥必须加密存储**:使用独立的加密密钥 3. **API Key 不得明文日志**:日志中应脱敏处理 4. **密码哈希不得使用弱算法**:禁止 MD5/SHA1 ## 8. 测试覆盖 ### 8.1 单元测试 | 测试文件 | 覆盖范围 | |----------|----------| | `jwt_auth_test.go` | JWT 解析和验证 | | `api_key_auth_test.go` | API Key 认证流程 | | `api_key_service_cache_test.go` | 缓存机制 | | `totp_service_test.go` | TOTP 验证 | ### 8.2 集成测试 | 测试文件 | 场景 | |----------|------| | `e2e_user_flow_test.go` | 完整用户认证流程 | | `auth_rate_limit_integration_test.go` | 速率限制验证 | ## 9. 监控与运维 ### 9.1 关键指标 | 指标 | 告警阈值 | 说明 | |------|----------|------| | `auth_login_failures` | > 10/min | 登录失败过多 | | `auth_api_key_validations` | - | API Key 验证次数 | | `auth_cache_hit_rate` | < 80% | 缓存命中率低 | | `auth_totp_errors` | > 5/min | TOTP 验证失败多 | ### 9.2 日志分析 关键日志字段: - `user_id`:用户 ID - `action`:认证动作 - `ip`:客户端 IP - `user_agent`:客户端标识 - `success`:是否成功 ## 10. 总结 认证与授权模块设计完善,具有以下特点: - **多层认证**:支持 JWT、API Key、OAuth、TOTP - **安全加固**:密码 bcrypt、密钥加密、速率限制 - **高性能缓存**:两级缓存提升验证效率 - **完整审计**:全面的认证事件日志 **潜在问题:** 1. 激活码和 API Key 验证未包含系统标识,可能被其他部署实例使用 2. 缺少登录尝试锁定机制(连续失败后临时封禁) **修改建议:** - 如需解决跨实例使用问题,需在 Key 中嵌入实例标识 - 添加登录失败锁定机制增强安全性 --- *文档版本:1.0* *最后更新:2025-01* *分析基于:Sub2API v0.1.104*