- Remove old review reports (keep latest only) - Move docs/ to deploy/docs-backup/ - Move performance-testing/ to deploy/ - Clean up test output files - Organize root directory
13 KiB
13 KiB
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)
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 白名单
- 支持速率限制
验证流程:
// 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:社区账号登录
实现结构:
// 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)
角色层级:
const (
RoleUser Role = "user" // 普通用户
RoleAdmin Role = "admin" // 管理员
RoleSuperAdmin Role = "super_admin" // 超级管理员
)
权限检查:
// 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 分组级别的访问控制
// API Key 绑定到分组
type APIKey struct {
GroupID *int64 // 所属分组
// 用户只能访问自己分组内的资源
}
3.3 API Key 管理
3.3.1 创建 API Key
// 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 启用流程
// 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 验证流程
// 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 密码安全
// 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 速率限制
// 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 审计日志
// 记录所有认证事件
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)
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:
// 用于外部系统(如支付系统)调用 Admin API
type AdminAPIKey struct {
Key: string // 格式:admin-<64位hex>
Role: string // admin 或 super_admin
}
使用方式:
curl -H "x-api-key: admin-xxxxxxxxxxxxxx" \
https://your-domain/api/v1/admin/users
6.2 自定义认证提供者
要添加新的认证方式,需要:
- 实现认证接口
type AuthProvider interface {
Authenticate(credentials) (*User, error)
Refresh(token) (*User, error)
}
- 注册到路由器
// server/routes/auth.go
router.POST("/auth/custom", customAuthHandler)
7. 修改和扩展指南
7.1 常见修改场景
场景 1:调整 API Key 缓存策略
修改文件:service/api_key_auth_cache_impl.go
func (s *APIKeyService) getAuthCache(key string) (*APIKeyAuthCacheEntry, bool) {
// 调整 L1 缓存大小
l1Size := 20000 // 从 10000 增加到 20000
// 调整 L1 TTL
l1TTL := 2 * time.Minute // 从 1 分钟增加到 2 分钟
}
场景 2:添加新的 OAuth 提供商
- 在
service/oauth/目录创建新服务 - 实现
OAuthProvider接口 - 在
auth_service.go注册
场景 3:调整速率限制
修改文件:middleware/rate_limiter.go
const (
UserRPM = 2000 // 从 1000 增加到 2000
APIKeyRPM = 1000 // 从 500 增加到 1000
)
7.2 安全注意事项
- JWT Secret 必须足够复杂:至少 256 位随机字符串
- TOTP 密钥必须加密存储:使用独立的加密密钥
- API Key 不得明文日志:日志中应脱敏处理
- 密码哈希不得使用弱算法:禁止 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:用户 IDaction:认证动作ip:客户端 IPuser_agent:客户端标识success:是否成功
10. 总结
认证与授权模块设计完善,具有以下特点:
- 多层认证:支持 JWT、API Key、OAuth、TOTP
- 安全加固:密码 bcrypt、密钥加密、速率限制
- 高性能缓存:两级缓存提升验证效率
- 完整审计:全面的认证事件日志
潜在问题:
- 激活码和 API Key 验证未包含系统标识,可能被其他部署实例使用
- 缺少登录尝试锁定机制(连续失败后临时封禁)
修改建议:
- 如需解决跨实例使用问题,需在 Key 中嵌入实例标识
- 添加登录失败锁定机制增强安全性
文档版本:1.0 最后更新:2025-01 分析基于:Sub2API v0.1.104