# B 端认证系统架构说明 本文档描述君鸿卡管系统 B 端认证的架构设计、技术决策和安全机制。 --- ## 系统概述 ### 核心特性 - **双令牌机制**:Access Token(短期)+ Refresh Token(长期) - **Redis 存储**:Token 存储在 Redis,支持快速撤销 - **多平台支持**:后台管理(Admin)和 H5 移动端 - **用户类型隔离**:不同平台限制不同的用户类型访问 - **无状态验证**:Token 验证无需查询数据库 ### 技术栈 | 组件 | 技术选型 | 理由 | |------|----------|------| | Token 生成 | UUID v4 | 高度随机,不可预测 | | Token 存储 | Redis | 快速查询,支持 TTL 自动过期 | | 密码哈希 | bcrypt | 慢哈希算法,抗暴力破解 | | HTTP 框架 | Fiber v2 | 高性能,类 Express API | | 数据库 | PostgreSQL | ACID 保证,可靠性高 | --- ## 架构图 ### 认证流程 ```mermaid sequenceDiagram participant Client as 客户端 participant Handler as AuthHandler participant Service as AuthService participant TokenMgr as TokenManager participant Redis as Redis participant DB as PostgreSQL Note over Client,DB: 1. 登录流程 Client->>Handler: POST /api/admin/login Handler->>Service: Login(username, password) Service->>DB: 查询账号信息 DB-->>Service: 返回账号(含密码哈希) Service->>Service: bcrypt 验证密码 Service->>DB: 查询用户权限 DB-->>Service: 返回权限列表 Service->>TokenMgr: GenerateTokenPair(userInfo) TokenMgr->>Redis: 存储 access_token(24h) TokenMgr->>Redis: 存储 refresh_token(7天) TokenMgr-->>Service: 返回 token 对 Service-->>Handler: 返回 token + 用户信息 Handler-->>Client: 200 OK + JSON响应 Note over Client,DB: 2. 访问受保护接口 Client->>Handler: GET /api/admin/me + Bearer Token Handler->>TokenMgr: ValidateAccessToken(token) TokenMgr->>Redis: GET auth:token:{token} Redis-->>TokenMgr: 返回 TokenInfo TokenMgr-->>Handler: 返回用户上下文 Handler->>Service: GetCurrentUser(userID) Service->>DB: 查询用户信息 DB-->>Service: 返回用户数据 Service-->>Handler: 返回用户+权限 Handler-->>Client: 200 OK + JSON响应 Note over Client,DB: 3. Token 刷新 Client->>Handler: POST /api/admin/refresh-token Handler->>Service: RefreshToken(refresh_token) Service->>TokenMgr: ValidateRefreshToken(token) TokenMgr->>Redis: GET auth:refresh:{token} Redis-->>TokenMgr: 返回 TokenInfo TokenMgr->>TokenMgr: GenerateNewAccessToken TokenMgr->>Redis: 存储新 access_token TokenMgr-->>Service: 返回新 access_token Service-->>Handler: 返回新 token Handler-->>Client: 200 OK + new token ``` ### 中间件执行顺序 ``` HTTP 请求 ↓ [Recover 中间件] ↓ [RequestID 中间件] ↓ [Logger 中间件] ↓ [Auth 中间件] ← 本系统 ├─ 提取 Token ├─ 验证 Token(调用 TokenManager) ├─ 检查用户类型 └─ 设置用户上下文 ↓ [路由处理器] ├─ 从 context 获取用户信息 └─ 执行业务逻辑 ↓ HTTP 响应 ``` --- ## 核心组件设计 ### 1. TokenManager(Token 管理器) **职责**: - Token 生成:使用 UUID v4 生成不可预测的 Token - Token 验证:从 Redis 查询并解析 TokenInfo - Token 撤销:单个撤销或批量撤销用户所有 Token - Token 刷新:验证 Refresh Token 并生成新的 Access Token **数据结构**: ```go type TokenInfo struct { UserID uint // 用户 ID UserType int // 用户类型(1-4) ShopID uint // 店铺 ID(代理商) EnterpriseID uint // 企业 ID(企业客户) Username string // 用户名 LoginTime time.Time // 登录时间 Device string // 设备类型 IP string // 登录 IP } ``` **Redis 存储结构**: ``` # Access Token Key: auth:token:{token_uuid} Value: JSON(TokenInfo) TTL: 24 小时 # Refresh Token Key: auth:refresh:{token_uuid} Value: JSON(TokenInfo) TTL: 7 天 # 用户 Token 列表(用于批量撤销) Key: auth:user:{user_id}:tokens Value: SET[token1, token2, ...] TTL: 7 天 ``` ### 2. AuthService(认证服务) **职责**: - 登录验证:查询账号、验证密码、生成 Token - 权限查询:查询用户的角色和权限列表 - Token 管理:登出、刷新、批量撤销 - 密码管理:修改密码(含旧 Token 撤销) **依赖注入**: ```go type Service struct { accountStore *postgres.AccountStore // 账号查询 accountRoleStore *postgres.AccountRoleStore // 账号-角色关联 rolePermStore *postgres.RolePermissionStore // 角色-权限关联 permissionStore *postgres.PermissionStore // 权限查询 tokenManager *auth.TokenManager // Token 管理 logger *zap.Logger // 日志记录 } ``` ### 3. Auth Middleware(认证中间件) **职责**: - Token 提取:从 `Authorization: Bearer {token}` 提取 Token - Token 验证:调用 TokenManager 验证合法性 - 用户类型检查:根据平台限制用户类型 - 上下文设置:将用户信息设置到 Fiber 和 Go Context **配置示例**: ```go // 后台认证中间件 AdminAuth := middleware.Auth(middleware.AuthConfig{ TokenValidator: func(token string) (*middleware.UserContextInfo, error) { // 验证 token tokenInfo, err := tokenManager.ValidateAccessToken(ctx, token) if err != nil { return nil, errors.New(errors.CodeInvalidToken, "令牌无效") } // 检查用户类型:后台只允许 SuperAdmin、Platform、Agent if tokenInfo.UserType != constants.UserTypeSuperAdmin && tokenInfo.UserType != constants.UserTypePlatform && tokenInfo.UserType != constants.UserTypeAgent { return nil, errors.New(errors.CodeForbidden, "权限不足") } return &middleware.UserContextInfo{...}, nil }, SkipPaths: []string{"/api/admin/login", "/api/admin/refresh-token"}, }) ``` --- ## 安全机制 ### 1. 密码安全 **Bcrypt 哈希**: - 使用 bcrypt 算法(cost=10)存储密码 - 每个密码有唯一的 salt,防止彩虹表攻击 - 慢哈希算法,增加暴力破解成本 ```go // 密码哈希(注册时) hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), 10) // 密码验证(登录时) err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) ``` ### 2. Token 安全 **不可预测性**: - 使用 UUID v4 生成,128 位随机数 - 碰撞概率极低(约 1/2^122) **短生命周期**: - Access Token:24 小时自动过期 - Refresh Token:7 天自动过期 - 修改密码后立即撤销所有旧 Token **传输安全**: - 仅通过 Authorization 请求头传递(不在 URL 中) - 生产环境强制 HTTPS ### 3. 用户类型隔离 | 平台 | 允许访问 | 拒绝访问 | |------|----------|----------| | 后台 | SuperAdmin(1), Platform(2), Agent(3) | Enterprise(4), PersonalCustomer | | H5 | Agent(3), Enterprise(4) | SuperAdmin(1), Platform(2), PersonalCustomer | ### 4. 防御措施 **防止暴力破解**: - 计划引入登录失败次数限制(待实现) - 使用慢哈希算法(bcrypt)增加单次尝试成本 **防止 Token 泄露**: - Token 不出现在日志中(敏感信息脱敏) - Token 不出现在 URL 中 - Redis 连接使用密码保护 **防止会话劫持**: - Token 绑定设备和 IP(存储在 TokenInfo 中,可用于审计) - 可选:实现设备指纹验证(待实现) --- ## 设计决策 ### 为什么选择 Redis 而非 JWT? | 对比项 | Redis Token | JWT | |--------|-------------|-----| | 撤销能力 | ✅ 立即生效 | ❌ 无法撤销 | | 性能 | ✅ 5ms(Redis 查询) | ✅ 0ms(本地验证) | | 存储负担 | ⚠️ Redis 内存 | ✅ 无服务端存储 | | 灵活性 | ✅ 可存储复杂信息 | ⚠️ Payload 有大小限制 | | 适用场景 | B 端系统(需要撤销) | C 端系统(高并发) | **决策理由**: - B 端用户数量有限(< 1000),Redis 内存负担可接受 - 修改密码、账号禁用等场景需要立即撤销 Token - 需要存储完整的用户上下文信息(ShopID、EnterpriseID 等) ### 为什么使用双令牌机制? **问题**:如果只有一个 Token: - 短生命周期:用户频繁掉线,体验差 - 长生命周期:Token 泄露风险增加 **解决方案**: - Access Token(24小时):用于 API 访问,频繁传输,短生命周期降低泄露风险 - Refresh Token(7天):用于刷新 Access Token,低频传输,长生命周期减少掉线 ### 为什么密码修改要撤销所有 Token? **安全原因**: - 假设:用户发现密码泄露,立即修改密码 - 如果不撤销旧 Token,攻击者仍可使用旧 Token 访问 **实现**: ```go func (s *Service) ChangePassword(ctx context.Context, userID uint, oldPassword, newPassword string) error { // 1. 验证旧密码 // 2. 哈希新密码 // 3. 更新数据库 // 4. 撤销所有旧 Token return s.tokenManager.RevokeAllUserTokens(ctx, userID) } ``` --- ## 性能考量 ### Redis 性能 **预期负载**: - 用户数:< 1000 - 每用户平均 Token 数:2-3 个 - 总 Token 数:< 3000 - Redis 内存占用:< 3MB(每个 TokenInfo 约 1KB) **性能指标**: - Token 验证:< 5ms(Redis GET 操作) - Token 生成:< 10ms(Redis SET + SADD 操作) - Token 撤销:< 5ms(Redis DEL 操作) ### 数据库查询优化 **登录流程优化**: 1. 账号查询:使用 `username` 或 `phone` 索引(< 10ms) 2. 权限查询:使用 `account_id` 索引(< 20ms) 3. 总耗时:< 50ms **缓存策略**(待实现): - 用户权限列表可缓存 30 分钟 - 减少数据库查询压力 --- ## 扩展性 ### 水平扩展 **无状态设计**: - 认证服务无状态,可水平扩展 - Token 存储在 Redis,所有实例共享 **Redis 集群**: - 当前使用单机 Redis - 需要时可升级为 Redis Cluster 或 Sentinel ### 功能扩展 **可选功能**: - [ ] 设备指纹验证 - [ ] 登录失败次数限制 - [ ] 异地登录提醒 - [ ] 在线设备管理 - [ ] Token 黑名单 --- ## 监控和审计 ### 关键指标 | 指标 | 说明 | 告警阈值 | |------|------|----------| | 登录成功率 | 成功次数 / 总次数 | < 95% | | Token 验证失败率 | 失败次数 / 总次数 | > 5% | | Redis 可用性 | Ping 响应时间 | > 10ms | | Token 平均验证时间 | P95 响应时间 | > 20ms | ### 审计日志 **记录事件**: - 用户登录(成功/失败) - Token 撤销(单个/批量) - 密码修改 - 账号状态变更 **日志格式**: ```json { "level": "info", "timestamp": "2026-01-15T16:15:00+08:00", "event": "user_login", "user_id": 1, "username": "admin", "ip": "127.0.0.1", "device": "web", "success": true } ``` --- ## 相关文档 - [API 文档](api/auth.md) - 完整的 API 接口说明 - [使用指南](auth-usage-guide.md) - 如何在代码中集成认证 - [错误处理指南](003-error-handling/使用指南.md) - 统一错误处理 --- **文档版本**: v1.0 **最后更新**: 2026-01-15 **维护者**: 君鸿卡管系统开发团队