- 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
16 KiB
16 KiB
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 数据模型
// 用户实体 - 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 用户注册流程
// 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 用户登录流程
// 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创建
// 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验证
// 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 用户分组管理
// 用户分组 - 用于资源隔离和配额控制
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 用户配额与限制
// 用户级别限制配置
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 用户属性管理
// 自定义用户属性 - 支持扩展字段
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 角色权限
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权限继承
// API Key继承用户的权限和配额
type APIKeyPermission struct {
UserID int64
GroupID *int64
Quota float64 // 继承用户的配额
RateLimit float64 // 继承用户的速率限制
Models []string // 继承分组的模型限制
}
5. 数据访问层
5.1 用户Repository
// 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
// 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)
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配置
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:调整用户并发限制
// 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:添加用户属性
// 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配额逻辑
// 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 注意事项
- 安全性:用户密码必须使用强哈希存储
- 数据一致性:API Key与用户关系需要级联处理
- 性能:用户列表查询需要分页和索引优化
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增强安全性
潜在改进点:
- 激活码和API Key目前没有包含系统标识,存在跨实例使用风险
- 用户分组权限控制可以更细粒度
修改建议:
- 如需解决跨实例使用问题,可在Key生成时嵌入实例ID
- 权限修改需要谨慎测试,避免影响现有功能
文档版本:1.0 最后更新:2025-01 分析基于:Sub2API v0.1.104