521 lines
13 KiB
Markdown
521 lines
13 KiB
Markdown
|
|
# 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*
|