Files
tokens-reef/deploy/docs-backup/MODULE_04_USER_APIKEY.md

557 lines
16 KiB
Markdown
Raw Permalink Normal View History

# Sub2API 模块分析报告用户与API Key管理模块
## 1. 模块概述
### 1.1 模块定位
用户与API Key管理模块是Sub2API系统的用户资源管理核心负责管理系统中所有用户账户、API Key的创建、分配、权限控制以及用户分组等操作。该模块与认证模块紧密配合共同构成系统的访问控制体系。
### 1.2 核心职责
- **用户生命周期管理**:用户注册、登录、信息修改、注销
- **API Key管理**:创建、分配、吊销、权限控制
- **用户分组管理**:用户分组、分组权限、组内资源分配
- **配额与限制**:用户级别的配额、并发限制、速率限制
- **用户属性管理**:自定义属性、标签、扩展信息
## 2. 代码结构分析
### 2.1 核心文件
| 文件路径 | 职责 | 代码行数 |
|---------|------|----------|
| `service/user.go` | 用户服务核心逻辑 | ~500行 |
| `service/api_key_service.go` | API Key服务 | ~900行 |
| `service/admin_service.go` | 管理后台用户操作 | ~2000行 |
| `handler/user_handler.go` | 用户相关API处理器 | ~400行 |
| `handler/admin/user_handler.go` | 管理后台用户处理器 | ~400行 |
| `handler/api_key_handler.go` | API Key处理器 | ~300行 |
| `handler/admin/apikey_handler.go` | 管理后台API Key处理器 | ~200行 |
| `repository/user_repo.go` | 用户数据访问层 | ~600行 |
| `repository/api_key_repo.go` | API Key数据访问层 | ~400行 |
### 2.2 数据模型
```go
// 用户实体 - ent/schema/user.go
type User struct {
ID int64
Email string // 邮箱(唯一)
PasswordHash string // 密码哈希
Name string // 显示名称
Avatar string // 头像URL
Status string // 用户状态active/disabled
Balance float64 // 账户余额
Concurrency int // 并发数限制
RateMultiplier float64 // 计费倍率
TOTPEnabled bool // 是否启用双因素认证
TOTPSecret string // TOTP密钥加密存储
LastLoginAt *time.Time // 最后登录时间
CreatedAt time.Time
UpdatedAt time.Time
}
// API Key实体 - ent/schema/apikey.go
type APIKey struct {
ID int64
Key string // Key值sk-开头)
Name string // 名称
UserID int64 // 所属用户
GroupID *int64 // 绑定分组
Quota float64 // 配额0为无限制
QuotaUsed float64 // 已使用配额
Status string // 状态active/disabled/quota_exhausted/expired
RateLimit5h float64 // 5小时速率限制
RateLimit1d float64 // 1天速率限制
RateLimit7d float64 // 7天速率限制
ExpiresAt *time.Time // 过期时间
IPWhitelist string // IP白名单JSON数组
LastUsedAt *time.Time // 最后使用时间
CreatedAt time.Time
UpdatedAt time.Time
}
```
## 3. 功能详细分析
### 3.1 用户注册与登录
#### 3.1.1 用户注册流程
```go
// service/auth_service.go - Register
func (s *AuthService) Register(ctx context.Context, req RegisterRequest) (*User, error) {
// 1. 验证邮箱格式
if !isValidEmail(req.Email) {
return nil, ErrInvalidEmail
}
// 2. 检查邮箱是否已存在
if exists, _ := s.userRepo.ExistsByEmail(ctx, req.Email); exists {
return nil, ErrEmailExists
}
// 3. 密码强度验证
if !isStrongPassword(req.Password) {
return nil, ErrWeakPassword
}
// 4. 密码哈希
passwordHash, _ := bcrypt.GenerateFromPassword([]byte(req.Password), 12)
// 5. 创建用户
user := &User{
Email: req.Email,
PasswordHash: string(passwordHash),
Name: req.Name,
Status: StatusActive,
Balance: 0,
Concurrency: 5, // 默认并发限制
}
return s.userRepo.Create(ctx, user)
}
```
#### 3.1.2 用户登录流程
```go
// service/auth_service.go - Login
func (s *AuthService) Login(ctx context.Context, email, password string) (*LoginResponse, error) {
// 1. 获取用户
user, err := s.userRepo.GetByEmail(ctx, email)
if err != nil {
return nil, ErrInvalidCredentials
}
// 2. 验证密码
if !bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)) {
// 记录登录失败
s.recordLoginFailure(ctx, user.ID)
return nil, ErrInvalidCredentials
}
// 3. 检查用户状态
if user.Status != StatusActive {
return nil, ErrUserDisabled
}
// 4. 如果启用了TOTP验证TOTP码
if user.TOTPEnabled {
// 返回需要TOTP验证的标记
return &LoginResponse{
RequireTOTP: true,
UserID: user.ID,
}, nil
}
// 5. 生成JWT Token
token, err := s.generateJWT(user)
if err != nil {
return nil, err
}
// 6. 更新最后登录时间
s.userRepo.UpdateLastLogin(ctx, user.ID)
return &LoginResponse{
Token: token,
User: user,
}, nil
}
```
### 3.2 API Key管理
#### 3.2.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. 检查用户API Key数量限制
count, _ := s.apiKeyRepo.CountByUser(ctx, userID)
if count >= maxAPIKeysPerUser {
return nil, ErrTooManyAPIKeys
}
// 3. 创建API Key
apiKey := &APIKey{
Key: key,
Name: req.Name,
UserID: userID,
GroupID: req.GroupID,
Quota: req.Quota,
Status: StatusActive,
RateLimit5h: req.RateLimit5h,
RateLimit1d: req.RateLimit1d,
RateLimit7d: req.RateLimit7d,
}
// 4. 处理IP白名单
if len(req.IPWhitelist) > 0 {
apiKey.IPWhitelist = json.Marshal(req.IPWhitelist)
}
// 5. 保存到数据库
created, err := s.apiKeyRepo.Create(ctx, apiKey)
if err != nil {
return nil, err
}
// 6. 返回时只显示一次Key
return created, nil
}
```
#### 3.2.2 API Key验证
```go
// service/api_key_service.go - ValidateKey
func (s *APIKeyService) ValidateKey(ctx context.Context, key string) (*APIKey, *User, error) {
// 1. 缓存查询
if cached := s.getCache(key); cached != nil {
return cached.APIKey, cached.User, nil
}
// 2. 数据库查询
apiKey, err := s.apiKeyRepo.GetByKey(ctx, key)
if err != nil {
return nil, nil, ErrInvalidKey
}
// 3. 验证状态
if apiKey.Status == StatusDisabled {
return nil, nil, ErrKeyDisabled
}
if apiKey.Status == StatusQuotaExhausted {
return nil, nil, ErrQuotaExhausted
}
if apiKey.Status == StatusExpired || (apiKey.ExpiresAt != nil && time.Now().After(*apiKey.ExpiresAt)) {
return nil, nil, ErrKeyExpired
}
// 4. 验证配额
if apiKey.Quota > 0 && apiKey.QuotaUsed >= apiKey.Quota {
return nil, nil, ErrQuotaExhausted
}
// 5. 获取用户信息
user, err := s.userRepo.GetByID(ctx, apiKey.UserID)
if err != nil || user.Status != StatusActive {
return nil, nil, ErrUserDisabled
}
// 6. 缓存结果
s.setCache(key, apiKey, user)
return apiKey, user, nil
}
```
### 3.3 用户分组管理
```go
// 用户分组 - 用于资源隔离和配额控制
type Group struct {
ID int64
Name string
Platform string // 所属平台anthropic/openai/gemini等
Status string // active/disabled
RateMultiplier float64 // 计费倍率
MaxConcurrency int // 最大并发数
MaxSessions int // 最大会话数
MaxRPM int // 每分钟最大请求数
Models []string // 允许的模型列表
IsExclusive bool // 是否独占(只能被一个用户使用)
}
```
### 3.4 用户配额与限制
```go
// 用户级别限制配置
type UserQuota struct {
Balance float64 // 账户余额
Concurrency int // 最大并发数
RateMultiplier float64 // 计费倍率默认1.0
MonthlyQuota float64 // 月度配额
DailyLimit float64 // 每日限制
}
// 使用量检查
func (s *UserService) CheckQuota(ctx context.Context, userID int64, cost float64) error {
user, err := s.userRepo.GetByID(ctx, userID)
if err != nil {
return err
}
// 检查余额
if user.Balance > 0 && user.Balance < cost {
return ErrInsufficientBalance
}
// 检查并发限制
activeConns := s.getActiveConnections(userID)
if activeConns >= user.Concurrency {
return ErrConcurrencyExceeded
}
return nil
}
```
### 3.5 用户属性管理
```go
// 自定义用户属性 - 支持扩展字段
type UserAttribute struct {
ID int64
Name string // 属性名
Type string // 类型string/number/boolean
Required bool // 是否必填
Default string // 默认值
}
// 用户属性值
type UserAttributeValue struct {
UserID int64
AttributeID int64
Value string
}
```
## 4. 权限控制
### 4.1 角色权限
```go
const (
RoleUser = "user" // 普通用户
RoleAdmin = "admin" // 管理员
RoleSuperAdmin = "super_admin" // 超级管理员
)
// 权限检查
func (s *UserService) CheckPermission(userID int64, action string) bool {
user, _ := s.userRepo.GetByID(ctx, userID)
switch action {
case "user:read":
return true
case "user:write":
return user.Role == RoleAdmin || user.Role == RoleSuperAdmin
case "admin:*":
return user.Role == RoleSuperAdmin
default:
return false
}
}
```
### 4.2 API Key权限继承
```go
// API Key继承用户的权限和配额
type APIKeyPermission struct {
UserID int64
GroupID *int64
Quota float64 // 继承用户的配额
RateLimit float64 // 继承用户的速率限制
Models []string // 继承分组的模型限制
}
```
## 5. 数据访问层
### 5.1 用户Repository
```go
// repository/user_repo.go
type UserRepository interface {
Create(ctx context.Context, user *User) (*User, error)
GetByID(ctx context.Context, id int64) (*User, error)
GetByEmail(ctx context.Context, email string) (*User, error)
Update(ctx context.Context, user *User) error
Delete(ctx context.Context, id int64) error
ExistsByEmail(ctx context.Context, email string) (bool, error)
List(ctx context.Context, params PaginationParams, filters UserFilters) ([]User, int64, error)
UpdateBalance(ctx context.Context, userID int64, amount float64) error
UpdateConcurrency(ctx context.Context, userID int64, concurrency int) error
}
```
### 5.2 API Key Repository
```go
// repository/api_key_repo.go
type APIKeyRepository interface {
Create(ctx context.Context, key *APIKey) (*APIKey, error)
GetByID(ctx context.Context, id int64) (*APIKey, error)
GetByKey(ctx context.Context, key string) (*APIKey, error)
GetByUserID(ctx context.Context, userID int64) ([]APIKey, error)
Update(ctx context.Context, key *APIKey) error
Delete(ctx context.Context, id int64) error
CountByUser(ctx context.Context, userID int64) (int, error)
List(ctx context.Context, params PaginationParams, filters APIKeyFilters) ([]APIKey, int64, error)
}
```
## 6. 配置参数
### 6.1 用户配置config.yaml
```yaml
user:
# 注册配置
registration:
enabled: true # 允许注册
email_verification: false # 邮箱验证
password_min_length: 8
password_require_complexity: true
# 登录配置
login:
max_attempts: 5 # 最大登录尝试
lockout_duration: 15m # 锁定时长
session_timeout: 24h # 会话超时
# 用户限制
limits:
max_api_keys_per_user: 50 # 每用户最大API Key数
default_concurrency: 5 # 默认并发数
default_balance: 0 # 默认余额
```
### 6.2 API Key配置
```yaml
api_key:
# 默认速率限制
default_rate_limits:
rate_limit_5h: 100000
rate_limit_1d: 500000
rate_limit_7d: 3500000
# 缓存配置
cache:
enabled: true
l1_size: 10000
l1_ttl: 1m
l2_ttl: 5m
```
## 7. 修改和扩展指南
### 7.1 常见修改场景
**场景1调整用户并发限制**
```go
// service/user.go - UpdateConcurrency
func (s *UserService) UpdateConcurrency(ctx context.Context, userID int64, concurrency int) error {
// 验证限制范围
if concurrency < 1 || concurrency > 100 {
return ErrInvalidConcurrency
}
user, _ := s.userRepo.GetByID(ctx, userID)
user.Concurrency = concurrency
return s.userRepo.Update(ctx, user)
}
```
**场景2添加用户属性**
```go
// 1. 在 ent/schema/user.go 添加字段
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("custom_field").Optional(),
}
}
// 2. 在 handler 中添加访问接口
router.PUT("/users/:id/custom-field", updateCustomField)
```
**场景3修改API Key配额逻辑**
```go
// service/api_key_service.go - CheckQuota
func (s *APIKeyService) CheckQuota(ctx context.Context, key *APIKey, cost float64) error {
// 修改配额检查逻辑
if key.Quota > 0 {
// 改为允许一定比例的超支
allowedOverdraft := key.Quota * 0.1 // 10%超支额度
if key.QuotaUsed + cost > key.Quota + allowedOverdraft {
return ErrQuotaExhausted
}
}
return nil
}
```
### 7.2 注意事项
1. **安全性**:用户密码必须使用强哈希存储
2. **数据一致性**API Key与用户关系需要级联处理
3. **性能**:用户列表查询需要分页和索引优化
## 8. 测试覆盖
### 8.1 单元测试
| 测试文件 | 覆盖范围 |
|----------|----------|
| `auth_service_register_test.go` | 用户注册逻辑 |
| `api_key_service_test.go` | API Key CRUD |
| `user_service_test.go` | 用户管理逻辑 |
### 8.2 集成测试
| 测试文件 | 场景 |
|----------|------|
| `e2e_user_flow_test.go` | 完整用户使用流程 |
## 9. 监控与运维
### 9.1 关键指标
| 指标 | 告警阈值 | 说明 |
|------|----------|------|
| `user_register_count` | - | 用户注册数 |
| `user_login_failures` | > 10/min | 登录失败数 |
| `api_key_count` | - | API Key总数 |
| `api_key_quota_exhausted` | > 20% | 配额耗尽比例 |
### 9.2 运维任务
| 任务 | 频率 | 说明 |
|------|------|------|
| 清理无效用户 | 每月 | 清理长期未登录用户 |
| 检查API Key | 每周 | 检查过期Key并通知 |
| 用户数据分析 | 每周 | 用户活跃度分析 |
## 10. 总结
用户与API Key管理模块特点
- **完整的用户生命周期**:从注册到注销的完整管理
- **灵活的权限控制**:基于角色和分组的权限体系
- **API Key安全**支持IP白名单、速率限制、配额控制
- **双因素认证**支持TOTP增强安全性
**潜在改进点:**
1. 激活码和API Key目前没有包含系统标识存在跨实例使用风险
2. 用户分组权限控制可以更细粒度
**修改建议:**
- 如需解决跨实例使用问题可在Key生成时嵌入实例ID
- 权限修改需要谨慎测试,避免影响现有功能
---
*文档版本1.0*
*最后更新2025-01*
*分析基于Sub2API v0.1.104*