Files
tokens-reef/deploy/docs-backup/MODULE_02_AUTH.md
Developer 349d783fd1 refactor: clean up project structure
- 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
2026-04-06 23:36:03 +08:00

521 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 条 │
│ - TTL1 分钟 │
│ - 命中率:~90% │
└─────────────────────────────────────┘
│ 缓存未命中
┌─────────────────────────────────────┐
│ L2 Cache (Redis) │
│ - 容量:无限制 │
│ - TTL5 分钟 │
└─────────────────────────────────────┘
│ 缓存未命中
┌─────────────────────────────────────┐
│ 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 {
// 使用 bcryptcost = 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 cost12可配置 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*