18 KiB
PRD 与实现差异报告
文档版本: v3.0 生成日期: 2026-03-29 审查范围: PRD.md vs 实际代码实现 审查方法: 代码级验证(Agent 辅助分析)
一、已实现功能 ✓
1.1 用户注册与登录
| PRD 功能 | 实现状态 | 代码证据 |
|---|---|---|
| 邮箱注册 + 激活验证 | ✓ | auth.go Register(), ActivateEmail |
| 手机号注册 | ✓ | sms.go SendCode, LoginByCode |
| 用户名注册 | ✓ | auth.go Register() |
| 密码登录 | ✓ | auth.go Login() |
| 验证码登录(邮箱) | ✓ | auth_email.go LoginByEmailCode() |
| 验证码登录(手机) | ✓ | sms.go LoginByCode() |
| 社交账号登录 | ✓ | auth.go OAuthLogin/OAuthCallback |
| TOTP 双因素认证 | ✓ | totp.go Setup/Enable/Disable/Verify |
| 密码强度验证 | ✓ | auth.go GetPasswordStrength() |
| 密码重置(邮箱) | ✓ | password_reset.go |
| 头像上传 | ✓ | avatar.go |
| 图形验证码 | ✓ | captcha.go |
1.2 社交登录集成
| 平台 | 实现状态 |
|---|---|
| 微信 (WeChat) | ✓ |
| ✓ | |
| 支付宝 (Alipay) | ✓ |
| 抖音 (Douyin) | ✓ |
| GitHub | ✓ |
| ✓ | |
| ✓ | |
| ✓ | |
| 微博 (Weibo) | ✓ |
1.3 授权与认证
| 功能 | 实现状态 | 代码证据 |
|---|---|---|
| JWT Access Token (RS256) | ✓ | jwt.go RS256 支持 |
| Refresh Token | ✓ | auth.go RefreshToken() |
| Token 黑名单 | ✓ | auth.go blacklistTokenClaims() |
| CSRF Token | ✓ | csrf.go |
| OAuth 2.0 | ✓ | auth.go OAuth* |
| 登录失败锁定 | ✓ | auth.go recordLoginAnomaly() |
1.4 权限管理 (RBAC)
| 功能 | 实现状态 | 代码证据 |
|---|---|---|
| 用户-角色-权限模型 | ✓ | role_permission.go |
| 角色 CRUD | ✓ | role.go |
| 权限 CRUD | ✓ | permission.go |
| 角色分配 | ✓ | user.go AssignRoles() |
| 权限校验中间件 | ✓ | auth.go RequirePermission() |
| 默认角色 | ✓ | domain/role.go PredefinedRoles |
| 角色继承数据结构 | ✓ | Role.ParentID, Role.Level 字段存在 |
1.5 用户管理
| 功能 | 实现状态 | 代码证据 |
|---|---|---|
| 用户列表(分页/筛选/排序) | ✓ | user.go ListUsers() |
| 创建/编辑/删除用户 | ✓ | user.go |
| 用户状态管理 | ✓ | user.go UpdateUserStatus() |
| 登录日志 | ✓ | login_log.go |
| 操作日志 | ✓ | operation_log.go middleware |
| 用户导入/导出 | ✓ | export.go |
| 密码历史记录 | ✓ | user.go 实际使用 |
1.6 系统集成
| 功能 | 实现状态 | 代码证据 |
|---|---|---|
| RESTful API | ✓ | Gin router |
| Swagger/OpenAPI | ✓ | swagger/* |
| Webhook 事件通知 | ✓ | webhook.go 完整实现 |
| Admin 管理后台 | ✓ | React frontend |
| 健康检查端点 | ✓ | /health, /health/live, /health/ready |
| Prometheus 指标 | ✓ | /metrics |
1.7 安全机制
| 功能 | 实现状态 | 代码证据 |
|---|---|---|
| 登录失败锁定 | ✓ | auth.go |
| 图形验证码 | ✓ | captcha.go |
| IP 白名单/黑名单 | ✓ | ip_filter.go |
| 接口限流 | ✓ | ratelimit.go |
| 敏感操作 2FA | ✓ | TOTP 校验 |
| Argon2id 密码加密 | ✓ | auth.go HashPassword |
二、未实现功能
2.1 角色继承逻辑 ⚠️ 部分实现
PRD 描述: 子角色自动继承父角色权限
实际情况:
Role结构有ParentID和Level字段 ✓GetRolePermissions()只获取直接分配的权限 ✗- 没有递归遍历父角色收集权限的逻辑
证据 (role_permission.go):
// GetPermissionIDsByRoleIDs 只获取直接关联的权限
err := r.db.WithContext(ctx).Model(&domain.RolePermission{}).
Where("role_id IN ?", roleIDs).
Pluck("permission_id", &permissionIDs).Error
影响: 父子角色权限继承不生效
2.2 密码重置(手机短信)
PRD 描述: 手机验证码重置密码
实际情况: 未实现
- 只有邮箱重置
password_reset.go - 没有短信验证码重置密码的 API
2.3 设备信任功能
PRD 描述:
- "记住此设备" 免二次验证
- 信任期限可配置(7-30 天)
- 一键下线所有其他设备
实际情况: 部分实现
- 设备管理 CRUD 已实现 ✓
- "记住设备" 功能未实现 ✗
- 信任期限配置未实现 ✗
- 一键下线其他设备未实现 ✗
2.4 自定义字段扩展
PRD 描述: 用户自定义字段,JSON 格式存储,字段类型验证
实际情况: 未实现
User结构没有custom_fields字段- 没有字段验证规则配置
2.5 自定义主题配置
PRD 描述: 自定义登录页面样式、Logo 替换、主题色
实际情况: 未实现
- 登录页面使用固定样式
2.6 SSO 单点登录
PRD 描述: CAS、SAML 协议支持
实际情况: 未实现
- 没有 CAS/SAML 相关代码
2.7 异地登录检测
PRD 描述: 记录常用地区,异地登录通知
实际情况: 未实现
login_logs表有location字段但未用于异常检测
2.8 异常设备检测
PRD 描述: 设备指纹识别,新设备验证,异常告警
实际情况: 未实现
- 有设备信息记录但无指纹识别
2.9 "记住登录状态" 功能
PRD 描述: 密码登录时可选 "记住我"
实际情况: 未实现
- Refresh Token 机制存在但前端无此选项
三、功能完成度统计
| 模块 | PRD 需求数 | 已实现数 | 完成率 |
|---|---|---|---|
| 用户注册与登录 | 12 | 11 | 92% |
| 社交登录集成 | 6 | 6 | 100% |
| 授权与认证 | 6 | 6 | 100% |
| 权限管理 | 7 | 6 | 86% |
| 用户管理 | 10 | 9 | 90% |
| 系统集成 | 6 | 6 | 100% |
| 安全与风控 | 10 | 9 | 90% |
| 监控与运维 | 4 | 4 | 100% |
| 总计 | 61 | 57 | 93% |
四、建议修复优先级
| 优先级 | 功能 | 原因 | 工作量 |
|---|---|---|---|
| 高 | 角色继承逻辑 | 数据结构已有,需补全查询逻辑 | 中 |
| 中 | 设备信任功能 | 安全增强 | 中 |
| 中 | 短信密码重置 | 用户体验 | 低 |
| 低 | 自定义字段 | 需要schema设计 | 高 |
| 低 | 自定义主题 | 边缘需求 | 中 |
| 低 | SSO | 复杂协议 | 高 |
五、代码质量问题(通过专业代码审查发现)
5.1 性能问题
5.1.1 N+1 查询问题 ⚠️
位置: internal/api/middleware/auth.go:131-177
问题描述: loadUserRolesAndPerms 方法每次认证请求触发 4 次数据库查询:
GetRoleIDsByUserID- 查询用户角色GetByIDs- 查询角色详情GetPermissionIDsByRoleIDs- 查询角色权限GetByIDs- 查询权限详情
证据:
func (m *AuthMiddleware) loadUserRolesAndPerms(ctx context.Context, userID int64) ([]string, []string) {
roleIDs, err := m.userRoleRepo.GetRoleIDsByUserID(ctx, userID) // 查询1
// ...
roles, err := m.roleRepo.GetByIDs(ctx, roleIDs) // 查询2 (批量)
// ...
permIDs, err := m.rolePermRepo.GetPermissionIDsByRoleIDs(ctx, roleIDs) // 查询3
// ...
perms, err := m.permRepo.GetByIDs(ctx, permIDs) // 查询4 (批量)
}
建议: 将这 4 个查询合并为 1 个 JOIN 查询,或增加 L1 缓存 TTL(如 15-30 分钟)。
补充位置: internal/service/role.go:194-212 也有类似问题,GetRolePermissions 方法在循环中单独查询每个权限。
5.1.2 正则表达式重复编译 ⚠️
位置: internal/security/validator.go:98-101, 129-136
问题描述: SanitizeSQL 和 SanitizeXSS 在每次调用时都在循环内使用 regexp.MustCompile,导致正则表达式重复编译,影响性能。
证据:
for _, pattern := range dangerousPatterns {
re := regexp.MustCompile(`(?i)` + pattern) // 每次调用都重新编译
result = re.ReplaceAllString(result, "")
}
建议: 预编译正则表达式并复用,或使用 regexp.Regexp 实例。
5.1.3 设备列表查询无分页限制 ⚠️
位置: internal/service/device.go:142-152
问题描述: GetUserDevices 方法虽然有 page 和 pageSize 参数,但如果传入负数或零值,可能导致全表扫描。
建议: 在 service 层增加参数校验,确保分页参数有效。
5.2 安全问题
5.2.1 敏感操作验证绕过风险 ⚠️
位置: internal/service/auth.go:1068-1102
问题描述: verifySensitiveAction 方法在密码和 TOTP 都为空时直接返回成功,可能导致敏感操作(如解绑社交账号)无需验证。
证据:
if password != "" {
// 验证密码
}
if code != "" {
// 验证TOTP
}
// 如果都没有,且用户有密码或TOTP,仍然返回nil
if hasPassword || hasTOTP {
return errors.New("password or TOTP verification is required")
}
return nil // 当用户没有密码也没有TOTP时,这里直接返回nil
影响: 如果用户没有设置密码也没有启用TOTP,可以无需任何验证即可解绑社交账号。
5.2.2 设备字段长度未校验 ⚠️
位置: internal/service/device.go:52-92
问题描述: CreateDeviceRequest 中 DeviceID、DeviceName 等字段没有长度校验,可能导致数据库存储问题。
证据:
type CreateDeviceRequest struct {
DeviceID string `json:"device_id" binding:"required"`
DeviceName string `json:"device_name"`
// 缺少 binding:"max=100" 等校验
}
5.2.3 登录日志异步写入失败无告警 ⚠️
位置: internal/service/auth.go:470-474
问题描述: writeLoginLog 方法使用 goroutine 异步写入日志,但失败时只是打印日志,没有告警机制。
证据:
go func() {
if err := s.loginLogRepo.Create(context.Background(), loginRecord); err != nil {
log.Printf("auth: write login log failed...") // 仅打印日志
}
}()
建议: 对于安全相关日志,应考虑使用专门的安全日志系统或至少记录指标。
5.3 代码质量问题
5.3.1 重复的用户名生成逻辑 ⚠️
位置: internal/service/auth.go:243-274
问题描述: generateUniqueUsername 中使用循环查询数据库检查用户名是否存在,每次循环都是一次数据库查询。最多可能执行 1000 次查询。
证据:
for i := 1; i <= 1000; i++ {
candidate := fmt.Sprintf("%s_%d", username, i)
exists, err = s.userRepo.ExistsByUsername(ctx, candidate)
// 每次循环都有一次数据库查询
}
建议: 使用数据库唯一索引 + 错误重试机制替代循环查询。
5.3.2 字符串处理重复 ⚠️
位置: 多处
问题描述: 代码中多次出现类似的字符串处理逻辑:
strings.TrimSpace+strings.ToLower组合- 重复的正则表达式模式
示例:
// auth.go 多次使用
strings.ToLower(strings.TrimSpace(provider))
strings.TrimSpace(oauthUser.Email)
建议: 提取公共工具函数复用。
5.3.3 错误处理不一致 ⚠️
位置: internal/service/auth.go 多处
问题描述: 部分函数在错误时返回具体错误消息,部分返回通用错误,API 响应不一致。
示例:
// 有些返回具体错误
return nil, errors.New("账号已锁定,请稍后再试")
// 有些返回通用错误
return nil, errors.New("auth service is not fully configured")
建议: 统一错误处理模式,使用错误码或自定义错误类型。
5.3.4 硬编码魔法数字 ⚠️
位置: 多处
问题描述: 代码中存在未定义常量的魔法数字。
示例:
// auth.go:262
for i := 1; i <= 1000; i++ { // 1000 是什么?
// role.go:72-73
if req.ParentID != nil {
role.Level = 2 // Level = 2 是什么意思?
}
建议: 使用有名称的常量替代魔法数字。
5.4 代码审查总结
| 问题类型 | 数量 | 严重程度 |
|---|---|---|
| 性能问题 | 3 | 中 |
| 安全问题 | 3 | 中-高 |
| 代码质量问题 | 4 | 低-中 |
关键问题:
- 必须修复: 敏感操作验证绕过风险 (5.2.1)
- 应该修复: N+1 查询问题 (5.1.1)、正则表达式重复编译 (5.1.2)
- 建议修复: 用户名生成逻辑 (5.3.1)、错误处理不一致 (5.3.3)
六、新发现的安全漏洞(Agent 详细审查)
6.1 高危安全问题
[SEC-01] OAuth ValidateToken 方法形同虚设 ⚠️⚠️
文件: internal/auth/oauth.go:436-446
问题描述: ValidateToken 方法始终返回 true,完全没有验证 token 的有效性。
证据:
func (m *DefaultOAuthManager) ValidateToken(token string) (bool, error) {
if len(token) == 0 {
return false, nil
}
return true, nil // <-- 始终返回 true
}
影响: 调用方以为做了验证,实际什么都没做。
[SEC-02] 敏感操作验证绕过 ⚠️⚠️
文件: internal/service/auth.go:1068-1102
问题描述: 当用户没有设置密码也没有启用 TOTP 时,verifySensitiveAction 直接返回成功。
证据:
if hasPassword || hasTOTP {
return errors.New("password or TOTP verification is required")
}
return nil // <-- 无密码无TOTP时直接通过
影响: 可以无需任何验证即可解绑社交账号。
[SEC-03] 恢复码明文存储 ⚠️⚠️
文件: internal/service/auth.go:1117-1132
问题描述: TOTP 恢复码以明文 JSON 存储在数据库中。
修复建议: 使用 bcrypt/Argon2 对恢复码进行哈希后存储。
[SEC-04] TOTP 算法使用 SHA1(已知弱点)⚠️
文件: internal/auth/totp.go:25
问题描述: 代码使用 SHA1 作为 TOTP 算法,Google Authenticator 等已迁移到 SHA256。
[SEC-05] X-Forwarded-For IP 伪造风险 ⚠️
文件: internal/api/middleware/ip_filter.go:50-65
问题描述: 中间件直接信任 X-Forwarded-For 请求头,攻击者可伪造任意 IP 绕过黑名单。
[SEC-06] JTI 包含可预测的时间戳 ⚠️
文件: internal/auth/jwt.go:58-66
问题描述: JTI 格式为 fmt.Sprintf("%x-%d", b, time.Now().UnixNano()),追加了可预测的时间戳。
[SEC-07] OAuth State 验证存在 TOCTOU 竞态条件 ⚠️
文件: internal/auth/oauth_utils.go:42-64
问题描述: 过期检查和删除操作不在同一个锁区域内,存在竞态条件。
[SEC-08] 刷新令牌接口缺少速率限制 ⚠️
文件: internal/api/router/router.go:108
问题描述: /auth/refresh 接口没有限流中间件。
6.2 中危安全问题
| ID | 问题 | 文件位置 |
|---|---|---|
| SEC-09 | CSRF Token 接口无 CSRF 保护 | auth.go:673-683 |
| SEC-10 | Session Presence Cookie 不是 HttpOnly | auth.go:117 |
| SEC-11 | rand.Read 错误被忽略 | oauth_utils.go:30 |
| SEC-12 | 日志泄露敏感信息 | 多处 |
| SEC-14 | 默认 Argon2 参数偏弱 (iterations=3) | password.go:29 |
| SEC-15 | 登录失败时泄露用户存在性 | auth.go:649-652 |
| SEC-16 | Cache 失效时锁定机制失效 | auth.go:640-647 |
七、新发现的性能问题(Agent 详细审查)
7.1 N+1 查询问题
[PERF-01] 每次认证请求触发 4 次数据库查询
文件: internal/api/middleware/auth.go:131-177
每个认证请求依次执行:
GetRoleIDsByUserID- 查询用户角色GetByIDs- 查询角色详情GetPermissionIDsByRoleIDs- 查询角色权限GetByIDs- 查询权限详情
[PERF-03] findUserForLogin 串行查询 3 次数据库
文件: internal/service/auth_runtime.go:32-54
按 username -> email -> phone 顺序串行查询,最坏情况需 3 次数据库往返。
7.2 其他性能问题
| ID | 问题 | 文件位置 |
|---|---|---|
| PERF-02 | OAuth State 存储无自动清理 | oauth_utils.go:23 |
| PERF-04 | 限流器清理策略不完善 | ratelimit.go:175 |
| PERF-05 | 重复缓存用户信息 | auth.go:686,1195 |
| PERF-06 | CacheManager 同步双写 L1+L2 | cache_manager.go:42 |
| PERF-07 | goroutine 无超时地写数据库 | auth.go:470 |
| PERF-08 | L1Cache 无自动清理 | l1.go |
| PERF-09 | AnomalyDetector records 无上限 | ip_filter.go:258 |
八、代码重复问题(Agent 详细审查)
8.1 严重重复
| 问题 | 文件 | 说明 |
|---|---|---|
| OAuth State 管理器重复 | state.go vs oauth_utils.go |
两套完全独立的实现 |
| Handler 授权函数重复 | authz.go vs user.go |
5个函数完全相同 |
| 分页逻辑重复 | 多个 service/handler | 每个文件都有相同的分页代码 |
| 密码强度验证重复 | password_policy.go vs auth.go |
相同逻辑重复实现 |
| 验证码生成重复 | email.go vs sms.go vs captcha.go |
三种不同实现 |
8.2 建议重构优先级
- 立即修复: OAuth State 重复、Handler 授权函数重复
- 短期修复: 分页逻辑统一、LIKE 查询转义
- 中期优化: 验证码生成统一、密码策略统一
九、代码质量审查总结
问题统计
| 类别 | 数量 | 严重程度 |
|---|---|---|
| 高危安全问题 | 8 | 高 |
| 中危安全问题 | 7 | 中 |
| 性能问题 | 12 | 中-低 |
| 代码重复 | 20+ | 中 |
| 代码质量问题 | 37+ | 低-中 |
关键修复清单
必须立即修复:
- [SEC-01] OAuth ValidateToken 始终返回 true
- [SEC-02] 敏感操作验证绕过漏洞
- [SEC-03] 恢复码明文存储
- [SEC-05] IP 伪造风险
应该修复:
- [PERF-01-03] N+1 查询和串行查询问题
- [PERF-07] goroutine 无超时问题
- 代码重复问题(state.go, authz.go 等)
建议修复:
- [SEC-14] Argon2 iterations 参数偏低
- [PERF-04-09] 其他性能和资源管理问题
- 错误处理不一致、魔法字符串等问题
本报告通过以下方式验证:
- 代码级分析(Agent 工具遍历所有相关文件)
- API endpoint 对比 router.go
- 数据模型检查 domain/*.go
- 业务逻辑检查 service/*.go
- 代码质量审查(使用 Simplify Skill 进行专业化审查)
- 代码重复和可复用性分析
- 安全漏洞和性能问题分析
- 代码质量和设计模式审查
本报告由系统审查生成,审查日期:2026-03-29 版本历史: v1.0 初始版本, v2.0 功能差异分析, v3.0 增加代码质量审查, v3.1 增加详细安全/性能审查