# 认证业务模块 (Auth Business Module) ## 架构层级 **Business Layer(业务层)** ## 职责定位 业务层负责实现核心业务逻辑和流程控制: 1. **业务流程**:实现完整的业务流程和规则 2. **服务协调**:协调多个核心服务完成业务功能 3. **数据转换**:将核心层数据转换为业务数据 4. **业务验证**:实现业务规则验证 5. **事务管理**:处理跨服务的事务逻辑 ## 模块组成 ``` src/business/auth/ ├── login.service.ts # 登录业务服务 ├── register.service.ts # 注册业务服务 ├── auth.module.ts # 业务模块配置 └── README.md # 模块文档 ``` ## 对外提供的接口 ### LoginService #### login(loginRequest: LoginRequest): Promise> 处理用户登录请求,验证用户凭据并生成JWT令牌,支持Zulip账号验证和更新。 #### githubOAuth(oauthRequest: GitHubOAuthRequest): Promise> 使用GitHub账户登录或注册,自动创建用户账号并生成JWT令牌。 #### verificationCodeLogin(loginRequest: VerificationCodeLoginRequest): Promise> 使用邮箱或手机号和验证码进行登录,无需密码即可完成认证。 #### sendPasswordResetCode(identifier: string): Promise> 向用户邮箱或手机发送密码重置验证码,支持测试模式和真实发送模式。 #### resetPassword(resetRequest: PasswordResetRequest): Promise 使用验证码重置用户密码,验证验证码有效性后更新密码。 #### changePassword(userId: bigint, oldPassword: string, newPassword: string): Promise 修改用户密码,需要验证旧密码正确性后才能更新为新密码。 #### refreshAccessToken(refreshToken: string): Promise> 使用有效的刷新令牌生成新的访问令牌,实现无感知的令牌续期。 #### sendLoginVerificationCode(identifier: string): Promise> 向用户邮箱或手机发送登录验证码,用于验证码登录功能。 ### RegisterService #### register(registerRequest: RegisterRequest): Promise> 处理用户注册请求,创建游戏账号和Zulip账号,支持邮箱验证和自动回滚。 #### sendEmailVerification(email: string): Promise> 向指定邮箱发送验证码,支持测试模式和真实发送模式。 #### verifyEmailCode(email: string, code: string): Promise 验证邮箱验证码的有效性,用于邮箱验证流程。 #### resendEmailVerification(email: string): Promise> 重新向指定邮箱发送验证码,用于验证码过期或未收到的情况。 ## 依赖关系 ``` Gateway Layer (auth.gateway.module) ↓ 使用 Business Layer (auth.module) ↓ 依赖 Core Layer (login_core.module, zulip_core.module) ``` ## 使用的项目内部依赖 ### LoginCoreService (来自 core/login_core) 核心登录服务,提供用户认证、JWT令牌生成、密码验证、验证码管理等技术实现。 ### ZulipAccountService (来自 core/zulip_core) Zulip账号服务,提供Zulip账号创建、API Key管理、账号验证等功能。 ### ApiKeySecurityService (来自 core/zulip_core) API Key安全服务,负责Zulip API Key的加密存储和Redis缓存管理。 ### ZulipAccountsService (来自 core/db/zulip_accounts) Zulip账号数据访问服务,提供游戏账号与Zulip账号的关联管理。 ### Users (来自 core/db/users) 用户实体,定义用户数据结构和数据库映射关系。 ## 核心原则 ### 1. 专注业务逻辑,不处理HTTP协议 ```typescript // ✅ 正确:返回统一的业务响应 async login(loginRequest: LoginRequest): Promise> { try { // 1. 调用核心服务进行认证 const authResult = await this.loginCoreService.login(loginRequest); // 2. 验证Zulip账号 await this.validateAndUpdateZulipApiKey(authResult.user); // 3. 生成JWT令牌 const tokenPair = await this.loginCoreService.generateTokenPair(authResult.user); // 4. 返回业务响应 return { success: true, data: { user: this.formatUserInfo(authResult.user), ...tokenPair }, message: '登录成功' }; } catch (error) { return { success: false, message: error.message, error_code: 'LOGIN_FAILED' }; } } ``` ### 2. 协调多个核心服务 ```typescript async register(registerRequest: RegisterRequest): Promise> { // 1. 初始化Zulip管理员客户端 await this.initializeZulipAdminClient(); // 2. 调用核心服务进行注册 const authResult = await this.loginCoreService.register(registerRequest); // 3. 创建Zulip账号 await this.createZulipAccountForUser(authResult.user, registerRequest.password); // 4. 生成JWT令牌 const tokenPair = await this.loginCoreService.generateTokenPair(authResult.user); // 5. 返回完整的业务响应 return { success: true, data: { ... }, message: '注册成功' }; } ``` ### 3. 统一的响应格式 ```typescript interface ApiResponse { success: boolean; data?: T; message: string; error_code?: string; } ``` ## 业务服务 ### LoginService 负责登录相关的业务逻辑: - `login()` - 用户登录 - `githubOAuth()` - GitHub OAuth登录 - `verificationCodeLogin()` - 验证码登录 - `sendPasswordResetCode()` - 发送密码重置验证码 - `resetPassword()` - 重置密码 - `changePassword()` - 修改密码 - `refreshAccessToken()` - 刷新访问令牌 - `sendLoginVerificationCode()` - 发送登录验证码 ### RegisterService 负责注册相关的业务逻辑: - `register()` - 用户注册 - `sendEmailVerification()` - 发送邮箱验证码 - `verifyEmailCode()` - 验证邮箱验证码 - `resendEmailVerification()` - 重新发送邮箱验证码 ## 核心特性 ### Zulip集成 - **自动创建Zulip账号**:注册时同步创建Zulip聊天账号 - **API Key管理**:安全存储和验证Zulip API Key - **账号关联**:建立游戏账号与Zulip账号的映射关系 - **失败回滚**:Zulip账号创建失败时自动回滚游戏账号 ### JWT令牌管理 - **双令牌机制**:访问令牌(短期)+ 刷新令牌(长期) - **无感知续期**:通过刷新令牌自动更新访问令牌 - **令牌验证**:完整的令牌签名和过期时间验证 ### 统一响应格式 - **ApiResponse接口**:统一的业务响应格式 - **错误代码**:标准化的错误代码定义 - **成功/失败标识**:明确的success字段 ### 数据转换和格式化 - **用户信息格式化**:将Core层数据转换为业务数据 - **BigInt处理**:自动将bigint类型转换为string - **敏感信息过滤**:响应中不包含密码等敏感数据 ### 完整的错误处理 - **业务异常捕获**:捕获所有业务逻辑异常 - **详细日志记录**:记录操作ID、用户ID、错误信息、执行时间 - **友好错误消息**:返回用户可理解的错误提示 ## 业务流程示例 ### 用户注册流程 ``` 1. 接收注册请求 ↓ 2. 初始化Zulip管理员客户端 ↓ 3. 调用LoginCoreService.register()创建游戏用户 ↓ 4. 创建Zulip账号并建立关联 ├─ 创建Zulip账号 ├─ 获取API Key ├─ 存储到Redis └─ 创建数据库关联记录 ↓ 5. 生成JWT令牌对 ↓ 6. 返回注册成功响应 ``` ### 用户登录流程 ``` 1. 接收登录请求 ↓ 2. 调用LoginCoreService.login()验证用户 ↓ 3. 验证并更新Zulip API Key ├─ 查找Zulip账号关联 ├─ 从Redis获取API Key ├─ 验证API Key有效性 └─ 如果无效,重新生成 ↓ 4. 生成JWT令牌对 ↓ 5. 返回登录成功响应 ``` ## 与其他层的交互 ### 与Gateway层的交互 Gateway层调用Business层服务: ```typescript // Gateway Layer @Post('login') async login(@Body() loginDto: LoginDto, @Res() res: Response): Promise { const result = await this.loginService.login({ identifier: loginDto.identifier, password: loginDto.password }); this.handleResponse(result, res); } ``` ### 与Core层的交互 Business层调用Core层服务: ```typescript // Business Layer async login(loginRequest: LoginRequest): Promise> { // 调用核心服务 const authResult = await this.loginCoreService.login(loginRequest); const tokenPair = await this.loginCoreService.generateTokenPair(authResult.user); // 返回业务响应 return { success: true, data: { ... } }; } ``` ## 最佳实践 1. **业务逻辑集中**:所有业务规则都在Business层实现 2. **服务协调**:协调多个Core层服务完成复杂业务 3. **错误处理**:捕获异常并转换为业务错误 4. **日志记录**:记录关键业务操作和错误 5. **事务管理**:处理跨服务的数据一致性 6. **数据转换**:将Core层数据转换为业务数据 ## 潜在风险 ### Zulip账号创建失败风险 - **风险描述**:注册流程中Zulip账号创建可能失败 - **影响范围**:导致注册流程中断,已创建的游戏账号需要回滚 - **缓解措施**:完整的事务回滚机制和错误日志记录 ### API Key验证失败风险 - **风险描述**:登录时Zulip API Key可能已失效或不存在 - **影响范围**:用户无法使用Zulip聊天功能 - **缓解措施**:API Key验证失败不影响登录流程,记录警告日志,尝试重新生成 ### 跨服务事务一致性风险 - **风险描述**:涉及多个Core层服务的协调操作,部分操作成功部分失败 - **影响范围**:数据不一致,如游戏账号创建成功但Zulip账号创建失败 - **缓解措施**:明确的操作顺序、完整的错误处理、自动回滚机制 ### 业务逻辑复杂度风险 - **风险描述**:登录和注册流程涉及多个步骤和服务,代码复杂度高 - **影响范围**:增加维护难度,容易引入bug - **缓解措施**:详细的注释、完整的测试覆盖(41个测试用例)、清晰的日志记录 ### 验证码发送失败风险 - **风险描述**:邮件服务不可用或配置错误导致验证码无法发送 - **影响范围**:用户无法完成邮箱验证、密码重置、验证码登录 - **缓解措施**:测试模式支持、详细的错误日志、邮件服务健康检查 ## 注意事项 - Business层不应该处理HTTP协议 - Business层不应该直接访问数据库(通过Core层) - Business层不应该包含技术实现细节 - 所有业务逻辑都应该有完善的错误处理 - 关键业务操作都应该有日志记录