36 KiB
Plan: IchniOnline API Integration
TL;DR
Quick Summary: Create an HTTP API client layer using BestHTTP and implement full auth flows (TapTap third-party login, password login, registration) to connect the Unity game client to the IchniOnline backend server.
Deliverables:
- BestHTTP-based API client with JSON serialization, JWT injection, error handling
- Request/Response DTOs matching server contracts
- Auth orchestration service (TapTap login, password login, register, logout)
- Extended LoginCacheData with JWT + server user data
- Updated LoginPage/StartUIPage to use new auth service
Estimated Effort: Medium Parallel Execution: YES — 4 waves Critical Path: asmdef → ApiClient → AuthService → UI Integration
Context
Original Request
对接 IchniOnline 后端的 API 接口,使用 BestHTTP 进行 HTTP 通信,编写详细计划。所有代码写在 Scripts/Online 目录内(IchniOnline.asmdef)。
Interview Summary
Key Discussions:
- 服务器开发地址:
localhost:5433,可配置 Base URL - ThirdParty.Unbound: 暂时跳过,当做登录失败处理
- JWT 存储: 扩展 LoginCacheData,加入 JWT + 用户数据,取代纯 TapTap 缓存
- 计划范围: TapTap 登录 + 密码登录/注册 + 基础 API 框架
Research Findings:
- BestHTTP 已安装为 embedded package (
com.tivadar.best.http),GUID:9069ac25d95ca17448a247f3bb1c769f,支持 async/await viaTask<T> - TapTap SDK 登录返回
TapTapAccount.accessToken(kid/tokenType/macKey/macAlgorithm),可直接映射到ThirdPartyLoginRequest - 服务端密码加密: XOR with session key(见
UserService.DecryptPassword) - 服务端响应格式:
GlobalResponse<T> { Code, Message, Data },Code 10000=Ok - JWT 验证: 服务端使用 JWT Bearer,后续 API 请求需在 Header 注入
Authorization: Bearer {token}
Metis Review
(Skipped per user request — direct exploration used instead)
Work Objectives
Core Objective
为 Unity 客户端创建 IchniOnline 后端 API 对接层,实现完整的认证流程(TapTap 第三方登录、密码登录、注册),让客户端和服务端互通。
Concrete Deliverables
Scripts/Online/IchniOnline.asmdef— 添加 BestHTTP 引用Scripts/Online/Network/ApiClient.cs— BestHTTP 封装单例Scripts/Online/Network/Models/ApiResponse.cs— 响应模型Scripts/Online/Network/Models/AuthDtos.cs— 请求/响应 DTOScripts/Online/Logic/AuthService.cs— 认证编排服务Scripts/Online/Logic/ThirdPartyServiceManager.cs— 修改:集成 AuthServiceScripts/Online/Logic/LoginCacheManager.cs— 修改:扩展 JWT 支持Scripts/Online/Models/LoginCacheData.cs— 修改:添加 JWT 字段
Definition of Done
- 编译零错误,无警告
- TapTap 登录后 JWT Token 成功写入本地缓存
- 密码登录流程完整(session key → XOR 加密 → login → JWT)
- 注册流程完整
- LoginPage 使用新 AuthService 驱动流程
- StartUIPage 校验会话有效性
Must Have
- ApiClient 支持 Base URL 配置(运行时可修改)
- ApiClient 自动注入 JWT Bearer 到 Authorization Header
- 所有 DTO 映射与服务器
GlobalResponse<T>完全匹配 - 密码 XOR 加密算法与服务器端一致
- AuthService 对外暴露事件(OnLoginSuccess/OnLoginFailed/etc.)
- LoginCacheData 向后兼容(旧缓存不报错)
Must NOT Have (Guardrails)
- 不要引入新的第三方 HTTP 库(只用 BestHTTP)
- 不要修改
LoginCacheEditor.cs(但可扩展) - 不要修改
UI/Base/UIPageBase.cs - 不要引入 Newtonsoft.Json(用 BestHTTP 内置的 LitJson 或 UnityEngine.JsonUtility)
- 不要阻塞主线程(所有 HTTP 请求必须异步)
Verification Strategy
Test Decision
- Infrastructure exists: YES (Unity Test Framework)
- Automated tests: None for network layer (needs running server)
- Agent-Executed QA: ALWAYS — each task verified via Playwright/browser or manual Unity Editor play mode evidence
QA Policy
Every task MUST include agent-executed QA scenarios.
- C# compilation through Unity Editor domain reload (verify zero compilation errors)
- Evidence: Unity Editor console logs, screenshots of play mode, runtime log output
Execution Strategy
Parallel Execution Waves
Wave 1 (Foundation — all parallel):
├── Task 1: IchniOnline.asmdef — 添加 BestHTTP 引用 [quick]
├── Task 2: ApiResponse.cs — GlobalResponse<T> 响应模型 [quick]
├── Task 3: AuthDtos.cs — 请求/响应 DTO [quick]
└── Task 4: LoginCacheData.cs — 扩展 JWT 字段 [quick]
Wave 2 (Core Client — depends on Wave 1):
├── Task 5: ApiClient.cs — BestHTTP 封装单例 [unspecified-high]
└── Task 6: LoginCacheManager.cs — 扩展 JWT 存取 [quick]
Note: Task 5+6 can run in parallel
Wave 3 (Auth Service — depends on Task 5+6):
├── Task 7: AuthService.cs — 认证编排服务 [unspecified-high]
Note: Depends on ApiClient + LoginCacheManager
Wave 4 (UI Integration — depends on Task 7):
├── Task 8: ThirdPartyServiceManager.cs — 集成 AuthService [quick]
├── Task 9: LoginPage.cs — 使用新 AuthService [visual-engineering]
└── Task 10: StartUIPage.cs — 校验会话有效性 [visual-engineering]
Wave FINAL:
├── F1: Plan Compliance Audit (oracle)
├── F2: Code Quality Review (unspecified-high)
├── F3: Real Manual QA (unspecified-high)
└── F4: Scope Fidelity Check (deep)
Dependency Matrix
- Task 1-4: - → 5, 6 → Wave 2
- Task 5, 6: 1-4 → 7 → Wave 3
- Task 7: 5, 6 → 8-10 → Wave 4
- Task 8-10: 7 → F1-F4 → Final
TODOs
-
1. IchniOnline.asmdef — 添加 BestHTTP 引用
What to do:
- 在
IchniOnline.asmdef的references数组中追加 BestHTTP 的 GUID - BestHTTP Runtime asmdef GUID:
9069ac25d95ca17448a247f3bb1c769f - 验证 Unity 编译无误,IchniOnline 程序集可以
using Best.HTTP;
Must NOT do:
- 不要修改其他 asmdef
- 不要修改 IchniOnline.Editor.asmdef
Recommended Agent Profile:
- Category:
quick- Reason: 单行 asmdef 修改,极简单的任务
- Skills: None needed
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1 (with Tasks 2, 3, 4)
- Blocks: Tasks 5, 6
- Blocked By: None
References:
Assets/Scripts/Online/IchniOnline.asmdef— 目标文件Packages/com.tivadar.best.http/Runtime/com.Tivadar.Best.HTTP.asmdef.meta:L1-7— GUID:9069ac25d95ca17448a247f3bb1c769f
Acceptance Criteria:
IchniOnline.asmdef的references数组包含"GUID:9069ac25d95ca17448a247f3bb1c769f"- Unity 编译完成后,IchniOnline 程序集内可以
using Best.HTTP;无报错
QA Scenarios:
Scenario: asmdef 引用验证 Tool: Bash (配合 Unity Editor) Preconditions: Unity Editor 已打开,IchniOnline.asmdef 已修改 Steps: 1. 在 Unity 中等待编译完成(AssetDatabase.Refresh 或观察 Console 无红错) 2. 打开 `Assets/Scripts/Online/IchniOnline.asmdef` 确认 references 包含 BestHTTP GUID Expected Result: 编译零错误,无 warning Evidence: .omo/evidence/task-1-asmdef-refs.png (Editor 无错误截图)Commit: YES (group with Tasks 2-4)
- Message:
feat(online): add BestHTTP reference to IchniOnline.asmdef - Files:
Assets/Scripts/Online/IchniOnline.asmdef - Pre-commit: 验证 Unity 编译通过
- 在
-
2. ApiResponse.cs — 创建服务端响应模型
What to do:
- 新建文件:
Assets/Scripts/Online/Network/Models/ApiResponse.cs - 定义
ResponseCodeenum(匹配服务端Models/Responses/ResponseCode.cs) - 定义
GlobalResponse<T>class(匹配服务端GlobalResponse<T>) - 定义
ApiResult<T>封装类,包含成功/失败状态 + 错误信息 - 使用
System.Text.Json或UnityEngine.JsonUtility做序列化(优先 JsonUtility 避免额外依赖) - 命名空间:
IchniOnline.Online.Network.Models
关键映射:
// 服务端 ResponseCode public enum ResponseCode { Ok = 10000, BadRequest = 10400, Unauthorized = 10401, Forbidden = 10403, NotFound = 10404, InternalServerError = 10500 } // 服务端 GlobalResponse<T> // 注意: Unity JsonUtility 不支持泛型直接反序列化,需要包装或使用封装层 // 方案: 实现一个非泛型的 ApiResponse 做中间反序列化,再通过 ApiResult<T> 取 DataMust NOT do:
- 不要引入 Newtonsoft.Json(项目中已无引用)
- 不要将序列化逻辑写死到 ApiClient 之外
Recommended Agent Profile:
- Category:
quick- Reason: 纯数据模型定义,无复杂逻辑
- Skills: None
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1 (with Tasks 1, 3, 4)
- Blocks: Tasks 5, 6
- Blocked By: None
References:
D:\Projects\IchniOnline\IchniOnline.Server\Models\Responses\GlobalResponse.cs— 服务端 GlobalResponse 实现D:\Projects\IchniOnline\IchniOnline.Server\Models\Responses\ResponseCode.cs— 服务端 ResponseCode enum
Acceptance Criteria:
ApiResponse.cs中定义ResponseCodeenum(Ok/BadRequest/Unauthorized/Forbidden/NotFound/InternalServerError)GlobalResponse<T>class 包含 Code/Message/Data 三个字段- Unity 编译通过,无错误
QA Scenarios:
Scenario: 编译验证 Tool: Unity Editor Preconditions: 文件创建完成,Unity 编译通过 Steps: 1. 在任意脚本中添加 `using IchniOnline.Online.Network.Models;` 2. 使用 `ResponseCode.Ok` 确认 enum 可用 Expected Result: 编译零错误 Evidence: .omo/evidence/task-2-compile.pngCommit: YES (group with Tasks 1, 3, 4)
- 新建文件:
-
3. AuthDtos.cs — 创建认证请求/响应 DTO
What to do:
- 新建文件:
Assets/Scripts/Online/Network/Models/AuthDtos.cs - 定义以下 DTO(匹配服务端 Models):
// 请求 DTO [System.Serializable] public class ThirdPartyLoginRequestDto { public string Token; // accessToken.kid public string TokenType; // accessToken.tokenType ("mac") public string MacKey; // accessToken.macKey public string MacAlgorithm; // accessToken.macAlgorithm ("hmac-sha-1") } [System.Serializable] public class LoginRequestDto { public string Username; public string EncryptedPassword; // Base64 of XOR'd bytes public string SessionKey; } [System.Serializable] public class RegisterRequestDto { public string Username; public string Password; public string DisplayName; } // 响应 DTO(与服务端 AuthResponse.cs 对应) [System.Serializable] public class SessionKeyResponseDto { public string sessionKey; public string expiresAt; } [System.Serializable] public class LoginResponseDto { public string Token; // JWT public UserResponseDto User; } [System.Serializable] public class UserResponseDto { public string UserId; public string Username; public string DisplayName; public string AvatarUrl; public int Permission; // 0=Guest, 1=Player, 2=Admin }Must NOT do:
- 不要包含非认证相关的 DTO(如 Beatmap 相关)
Recommended Agent Profile:
- Category:
quick- Reason: 纯数据结构定义
- Skills: None
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1 (with Tasks 1, 2, 4)
- Blocks: Tasks 5, 7
- Blocked By: None
References:
D:\Projects\IchniOnline\IchniOnline.Server\Models\Requests\ThirdPartyLoginRequest.csD:\Projects\IchniOnline\IchniOnline.Server\Models\Requests\LoginRequest.csD:\Projects\IchniOnline\IchniOnline.Server\Models\Requests\RegisterRequest.csD:\Projects\IchniOnline\IchniOnline.Server\Models\Responses\AuthResponse.cs
Acceptance Criteria:
- 所有 DTO 定义为
[System.Serializable] - Unity 编译通过
- 字段名小写(JSON 反序列化兼容服务端 PascalCase → JsonUtility 需字段名匹配)
QA Scenarios:
Scenario: 编译验证 Tool: Unity Editor Preconditions: 文件创建完成 Steps: Unity 编译自动触发 Expected Result: 无编译错误 Evidence: .omo/evidence/task-3-compile.pngCommit: YES (group with Tasks 1, 2, 4)
- 新建文件:
-
4. LoginCacheData.cs — 扩展 JWT 和服务器用户数据字段
What to do:
- 编辑
Assets/Scripts/Online/Models/LoginCacheData.cs - 添加以下字段:
public string jwtToken; // JWT Bearer token public string userId; // 服务端返回的 UserId (Guid 字符串) public string displayName; // 服务端返回的 DisplayName public string avatarUrl; // 服务端返回的 AvatarUrl public int permission; // 服务端返回的 Permission public bool hasServerSession; // 标记是否已完成服务端认证 - 更新
IsValid逻辑:hasServerSession && !string.IsNullOrEmpty(jwtToken) - 保持向后兼容:构造旧字段保留,无 session 时
hasServerSession=false - 添加
UpdateFromServerResponse(LoginResponseDto response)方法 - 添加
ClearServerSession()方法(仅清除 JWT 系列字段,保留 TapTap 原始信息)
Must NOT do:
- 不要删除已有字段 (openId/unionId/name/avatar/email/cacheTimestamp)
- 不要破坏
LoginCacheEditor.cs中使用的公开接口
Recommended Agent Profile:
- Category:
quick- Reason: 小幅度字段扩展,结构简单
- Skills: None
Parallelization:
- Can Run In Parallel: YES
- Parallel Group: Wave 1 (with Tasks 1, 2, 3)
- Blocks: Task 6
- Blocked By: None
References:
Assets/Scripts/Online/Models/LoginCacheData.cs— 当前文件D:\Projects\IchniOnline\IchniOnline.Server\Models\Responses\AuthResponse.cs— 服务端 LoginResponse/UserResponse
Acceptance Criteria:
LoginCacheData包含新字段jwtToken,userId,displayName,avatarUrl,permission,hasServerSession- 旧 ES3 缓存数据加载后不会报错(缺失字段为默认值,
hasServerSession=false) IsValid在hasServerSession为 true 时检查jwtToken非空- Unity 编译通过
QA Scenarios:
Scenario: 向后兼容测试 Tool: Unity Editor + Bash (ES3 操作) Preconditions: LoginCacheData 已修改,Unity 已编译 Steps: 1. 用 LoginCacheEditor.GenerateMockData 写入旧格式数据 2. 读取 LoginCacheManager.CachedData 3. 确认 hasServerSession=false,旧字段值正确 Expected Result: 旧缓存被正确加载,不丢失数据,不报错 Evidence: .omo/evidence/task-4-backward-compat.pngCommit: YES (group with Tasks 1, 2, 3)
- 编辑
-
5. ApiClient.cs — BestHTTP 封装单例
What to do:
- 新建文件:
Assets/Scripts/Online/Network/ApiClient.cs - 创建
IchniOnlineApiClient类(非 MonoBehaviour 单例,或挂载到 DontDestroyOnLoad 对象) - 核心功能:
- Base URL 配置:
public string BaseUrl { get; set; },初始值http://localhost:5433 - JWT 管理:
public string JwtToken { get; set; },设置后自动在请求头注入 - GET 请求:
Task<ApiResult<T>> GetAsync<T>(string endpoint) - POST 请求:
Task<ApiResult<T>> PostAsync<T>(string endpoint, object body) - 内部实现: 使用 BestHTTP 的
HTTPRequest+GetHTTPResponseAsync()- POST body 序列化:
request.RawData = Encoding.UTF8.GetBytes(JsonUtility.ToJson(body)) - Header 设置:
request.SetHeader("Content-Type", "application/json") - JWT 注入:
request.SetHeader("Authorization", $"Bearer {JwtToken}")
- POST body 序列化:
- 响应解析: 从
resp.DataAsText反序列化为GlobalResponse<T>,提取 Data - 错误处理:
- HTTP 状态码错误 → ApiResult 含错误信息
- 解析失败 → ApiResult 含异常信息
- 网络超时 → ApiResult.Timeout
- 服务器返回失败码 → 按 Code 分类处理
- Base URL 配置:
Error Handling Design:
public class ApiResult<T> { public bool IsSuccess; public T Data; public int Code; // ResponseCode public string Message; // 服务端返回的 Message public string ErrorDetail; // 客户端错误详情 public static ApiResult<T> Ok(T data) => ...; public static ApiResult<T> Fail(int code, string msg, string detail = null) => ...; }Must NOT do:
- 不要阻塞 Unity 主线程(所有请求使用 async/await)
- 不要硬编码 URL(BaseUrl 必须可配置)
- 不要在 ApiClient 内处理业务逻辑(仅做 HTTP 通信)
Recommended Agent Profile:
- Category:
unspecified-high- Reason: 需要理解 BestHTTP API、异步模式、JSON 序列化,有较多细节
- Skills: None (BestHTTP API 文档已通过前期研究覆盖)
Parallelization:
- Can Run In Parallel: YES (with Task 6)
- Parallel Group: Wave 2 (with Task 6)
- Blocks: Task 7
- Blocked By: Tasks 1, 2, 3
References:
Packages/com.tivadar.best.http/Runtime/HTTP/HTTPRequestAsyncExtensions.cs— BestHTTP async extension methodsPackages/com.tivadar.best.http/Runtime/HTTP/HTTPRequest.cs— HTTPRequest class APID:\Projects\IchniOnline\IchniOnline.Server\Models\Responses\GlobalResponse.cs— 服务端响应格式Assets/Scripts/Online/Network/Models/ApiResponse.cs— 客户端响应模型(同 Wave 1 Task 2)
Acceptance Criteria:
IchniOnlineApiClient可配置BaseUrlGetAsync<T>发送 GET 请求并正确解析GlobalResponse<T>PostAsync<T>发送 POST 请求,body 序列化为 JSON- JWT Token 自动注入到 Authorization Header
- 网络错误/服务端错误被正确封装为
ApiResult<T> - Unity 编译通过
QA Scenarios:
Scenario: GET 请求 + 响应解析 Tool: Unity Editor + Bash (可启动测试后端或 mock) Preconditions: IchniOnline 后端在 localhost:5433 运行(或 mock 端点) Steps: 1. 在 Unity Start() 中调用 ApiClient.GetAsync<object>("/api/test/health") 2. 检查 Console 输出请求/响应日志 Expected Result: 请求发送成功,响应被正确解析 Evidence: .omo/evidence/task-5-get-request.png Scenario: JWT 注入验证 Tool: Unity Editor Preconditions: ApiClient.JwtToken 设置为 "test-token" Steps: 1. 发起 PostAsync 请求 2. 检查请求 Header 包含 "Authorization: Bearer test-token" Expected Result: Authorization Header 正确注入 Evidence: .omo/evidence/task-5-jwt-header.pngCommit: YES (group with Task 6)
- Message:
feat(online): implement API client and extend login cache
- 新建文件:
-
6. LoginCacheManager.cs — 扩展 JWT 存取方法
What to do:
- 编辑
Assets/Scripts/Online/Logic/LoginCacheManager.cs - 添加新方法:
// 保存完整认证会话(JWT + 用户数据) public static void SaveAuthSession(string jwtToken, LoginResponseDto response) // 清除会话(保留 TapTap 原始数据,清除 JWT/服务端数据) public static void ClearSession() // 获取缓存的 JWT Token public static string CachedJwtToken { get; } // 检查是否有有效的服务端会话 public static bool HasValidSession { get; } - ES3 key 保持不变:
Ichni_LoginCache HasCachedLogin→ 改为检查HasValidSessionCachedData→ 保持返回完整数据SaveFromTapTapAccount→ 保持原有行为(只存 TapTap 数据,不清除已有 JWT)
Must NOT do:
- 不要修改 ES3 key 名称
- 不要改变已有方法的签名
Recommended Agent Profile:
- Category:
quick- Reason: 简单的方法扩展
- Skills: None
Parallelization:
- Can Run In Parallel: YES (with Task 5)
- Parallel Group: Wave 2 (with Task 5)
- Blocks: Task 7
- Blocked By: Tasks 1, 4
References:
Assets/Scripts/Online/Logic/LoginCacheManager.cs— 当前文件Assets/Scripts/Online/Models/LoginCacheData.cs— 扩展后的数据模型
Acceptance Criteria:
SaveAuthSession(jwt, response)正确写入 ES3CachedJwtToken从 ES3 读取正确HasValidSession在 jwt 为空或无 session 时返回 false- 编辑器中
Ichni/Login Cache菜单仍正常工作 - Unity 编译通过
QA Scenarios:
Scenario: 保存/读取 JWT 会话 Tool: Unity Editor Preconditions: 已有 LoginCacheData 模型扩展 Steps: 1. LoginCacheManager.SaveAuthSession("test-jwt", mockLoginResponse) 2. 读取 LoginCacheManager.CachedJwtToken 3. 读取 LoginCacheManager.HasValidSession Expected Result: jwt="test-jwt", HasValidSession=true Evidence: .omo/evidence/task-6-save-jwt.png Scenario: 清除会话 Steps: 1. LoginCacheManager.ClearSession() 2. 检查 HasValidSession Expected Result: HasValidSession=false, TapTap 原始数据保留 Evidence: .omo/evidence/task-6-clear.pngCommit: YES (group with Task 5)
- 编辑
-
7. AuthService.cs — 认证编排服务
What to do:
- 新建文件:
Assets/Scripts/Online/Logic/AuthService.cs - 创建
IchniOnlineAuthService类(非 MonoBehaviour 静态类 或 通过 ThirdPartyServiceManager 实例管理) - 核心接口:
public static class IchniOnlineAuthService { // 事件 public static event Action<LoginResponseDto> OnLoginSuccess; public static event Action<string> OnLoginFailed; // error message public static event Action OnLoginCanceled; // 属性 public static bool IsLoggingIn { get; } public static bool IsLoggedIn { get; } // HasValidSession // TapTap 第三方登录流程 // 1. 调用 ThirdPartyServiceManager.StartTapTapLogin() // 2. 在 OnLoginSuccess 回调中: // a. 从 TapTapAccount 取出 accessToken // b. 构造 ThirdPartyLoginRequestDto // c. 调用 ApiClient.PostAsync<LoginResponseDto>("/api/auth/third-party/login", body) // d. 成功 → LoginCacheManager.SaveAuthSession(jwt, response) // e. 失败 → 抛 OnLoginFailed // f. ThirdParty.Unbound → 抛 OnLoginFailed("TapTap account not bound") public static void LoginWithTapTap(); // 密码登录流程 // 1. GET /api/auth/session-key → 得到 sessionKey // 2. 密码 XOR 加密: // byte[] passwordBytes = Encoding.UTF8.GetBytes(password); // byte[] sessionBytes = Encoding.UTF8.GetBytes(sessionKey); // byte[] encrypted = new byte[passwordBytes.Length]; // for (int i = 0; i < passwordBytes.Length; i++) // encrypted[i] = (byte)(passwordBytes[i] ^ sessionBytes[i % sessionBytes.Length]); // string encryptedPassword = Convert.ToBase64String(encrypted); // 3. POST /api/auth/login with { Username, EncryptedPassword, SessionKey } // 4. 成功 → LoginCacheManager.SaveAuthSession(jwt, response) public static async void LoginWithPassword(string username, string password); // 注册流程 // POST /api/auth/register with { Username, Password, DisplayName } // 注意: 注册后不自动返回 JWT,需要用户手动登录 public static async void Register(string username, string password, string displayName); // 登出 public static void Logout(); // 密码 XOR 加密工具方法(可复用) public static string EncryptPassword(string password, string sessionKey); }Must NOT do:
- 不要直接调用 TapTap SDK 的 LoginWithScopes(由 ThirdPartyServiceManager 封装)
- 不要在 AuthService 中管理 UI 状态(只触发事件,由 LoginPage 处理 UI)
- 不要硬编码 API 路径(用字符串常量集中管理)
Recommended Agent Profile:
- Category:
unspecified-high- Reason: 涉及多步异步流程编排、事件管理、加密算法实现
- Skills: None
Parallelization:
- Can Run In Parallel: NO
- Parallel Group: Wave 3 (sequential)
- Blocks: Tasks 8, 9, 10
- Blocked By: Tasks 5, 6
References:
Assets/Scripts/Online/Logic/ThirdPartyServiceManager.cs— TapTap SDK 调用封装Assets/Scripts/Online/Network/ApiClient.cs— HTTP 通信(Task 5)Assets/Scripts/Online/Logic/LoginCacheManager.cs— 缓存管理(Task 6)D:\Projects\IchniOnline\IchniOnline.Server\Service\UserService.cs:213-225— 服务端 XOR 解密算法(客户端需反转实现加密)D:\Projects\IchniOnline\IchniOnline.Server\Controller\AuthController.cs— 服务端 API 端点定义
Acceptance Criteria:
LoginWithTapTap()完整流程: TapTap SDK → API call → JWT → 事件LoginWithPassword()完整流程: session key → XOR 加密 → API call → JWT → 事件Register()调用 POST /api/auth/registerLogout()清除 JWT + TapTap 登出EncryptPassword()与服务端DecryptPassword互为逆运算- 所有事件正确触发(OnLoginSuccess/OnLoginFailed/OnLoginCanceled)
- Unity 编译通过
QA Scenarios:
Scenario: 密码 XOR 加密验证 Tool: C# 脚本验证 Preconditions: AuthService.EncryptPassword 已实现 Steps: 1. 设 password="test123", sessionKey="base64encodedkey==" 2. 调用 EncryptPassword 得到 encrypted 3. 用服务端 DecryptPassword 逻辑解密: 取 encrypted Base64 → XOR with sessionKey bytes → 得到明文 Expected Result: 解密后明文等于原始 password Evidence: .omo/evidence/task-7-xor-verify.png Scenario: TapTap 登录流程(模拟) Tool: Unity Editor Play Mode Preconditions: ThirdPartyServiceManager 已初始化 Steps: 1. AuthService.LoginWithTapTap() 2. Console 观察: TapTap SDK 登录 → API POST 请求 → JWT 缓存 Expected Result: 流程完整无异常 Evidence: .omo/evidence/task-7-taaptap-flow.pngCommit: YES
- Message:
feat(online): implement auth service with TapTap/password/register flows - Files:
Assets/Scripts/Online/Logic/AuthService.cs - Pre-commit: Unity 编译检查
- 新建文件:
-
8. ThirdPartyServiceManager.cs — 集成 AuthService
What to do:
- 编辑
Assets/Scripts/Online/Logic/ThirdPartyServiceManager.cs - 在
StartTapTapLogin()的LoginWithScopes成功后,不再直接调用LoginCacheManager.SaveFromTapTapAccount(account)(该操作移至 AuthService 流程中) - 添加事件
OnTapTapAccessTokenReceived(AccessToken token)或修改流程,使 AuthService 能拿到 accessToken - 可选方案 A: ThirdPartyServiceManager 保留纯 SDK 封装,AuthService 通过
TapTapLogin.Instance.GetCurrentTapAccount()获取 account - 可选方案 B: ThirdPartyServiceManager 的
OnLoginSuccess事件中附带 accessToken - 推荐方案 B: 扩展
OnLoginSuccess事件参数或添加新事件// 新增事件: 携带 accessToken(供 AuthService 使用) public event Action<TapTapAccount, AccessToken> OnLoginWithToken; StartTapTapLogin()保持不变(依然触发 OnLoginSuccess/OnLoginCanceled/OnLoginFailed)
Must NOT do:
- 不要移除已有的事件(OnLoginSuccess/OnLoginCanceled/OnLoginFailed)
- 不要改变 TapTap SDK 初始化逻辑
Recommended Agent Profile:
- Category:
quick- Reason: 小幅接口扩展
- Skills: None
Parallelization:
- Can Run In Parallel: YES (with Tasks 9, 10)
- Parallel Group: Wave 4 (with Tasks 9, 10)
- Blocks: None
- Blocked By: Task 7
References:
Assets/Scripts/Online/Logic/ThirdPartyServiceManager.cs— 当前文件D:\Projects\Open\TapSDKLogin-Unity\Runtime\Public\TapTapAccount.cs— TapTapAccount 结构(含 accessToken 属性)
Acceptance Criteria:
OnLoginWithToken事件在 TapTap 登录成功后触发- 事件参数包含完整的
TapTapAccount和AccessToken - Unity 编译通过
QA Scenarios:
Scenario: 事件触发测试 Tool: Unity Editor Play Mode Preconditions: ThirdPartyServiceManager 已初始化 Steps: 1. 订阅 ThirdPartyServiceManager.Instance.OnLoginWithToken 2. 调用 StartTapTapLogin() 3. TapTap 登录成功后检查事件是否触发 Expected Result: 事件触发,accessToken.kid/macKey/macAlgorithm 非空 Evidence: .omo/evidence/task-8-event.pngCommit: YES (group with Tasks 9, 10)
- Message:
feat(ui): integrate auth service into login UI
- 编辑
-
9. LoginPage.cs — 使用新 AuthService 驱动流程
What to do:
- 编辑
Assets/Scripts/UI/LoginPage/LoginPage.cs - 修改
OnTapTapClicked():- 不再直接调用
ThirdPartyServiceManager.Instance.StartTapTapLogin() - 改为调用
IchniOnlineAuthService.LoginWithTapTap()
- 不再直接调用
- 修改
OnTapTapLoginSuccess(TapTapAccount account):- 不再立即 FadeOut(改为等待 AuthService 的服务端验证完成)
- 改为
IchniOnlineAuthService.OnLoginSuccess += OnApiLoginSuccess
- 添加新回调
OnApiLoginSuccess(LoginResponseDto response):- 服务端验证成功后 FadeOut + 恢复 StartPage
- 添加 UI 加载状态:
- 显示加载指示器(或按钮禁用+文字变化)在等待服务端响应期间
- 事件订阅:
- 订阅
AuthService.OnLoginSuccess/OnLoginFailed/OnLoginCanceled - 替代原有的 ThirdPartyServiceManager 事件(或共存)
- 订阅
- 账户密码登录 UI:
- 如果 LoginPage 上已有用户名/密码输入框 → 绑定到
IchniOnlineAuthService.LoginWithPassword() - 如果没有 → 增加简单的用户名/密码输入框 + 登录按钮
- 如果 LoginPage 上已有用户名/密码输入框 → 绑定到
Must NOT do:
- 不要删除 closeButton 和原有的 UI 结构
- 不要修改 UIPageBase 基类
Recommended Agent Profile:
- Category:
visual-engineering- Reason: 涉及 UI 逻辑更新和用户交互流程
- Skills: None
Parallelization:
- Can Run In Parallel: YES (with Tasks 8, 10)
- Parallel Group: Wave 4 (with Tasks 8, 10)
- Blocks: None
- Blocked By: Task 7
References:
Assets/Scripts/UI/LoginPage/LoginPage.cs— 当前文件Assets/Scripts/Online/Logic/AuthService.cs— 认证服务(Task 7)Assets/Scripts/UI/StartPage/StartUIPage.cs— StartPage 交互恢复Assets/Scripts/UI/StartPage/StartUIPage.cs:TouchToStart()— 缓存检测入口
Acceptance Criteria:
- TapTap 按钮触发
AuthService.LoginWithTapTap()而非直接调用 ThirdPartyServiceManager - 登录请求加载状态有 UI 反馈
- 服务端返回成功后 FadeOut + 恢复 StartPage
- 失败时恢复按钮交互
- Unity 编译通过
QA Scenarios:
Scenario: TapTap 登录 UI 流程 Tool: Unity Editor Play Mode Preconditions: LoginPage 在 MenuScene 中打开 Steps: 1. 点击 TapTap 按钮 2. 观察按钮变为非交互状态 3. TapTap SDK 登录窗口出现 4. 完成 TapTap 登录 → 等待服务端验证 5. 成功后 LoginPage 淡出 → 恢复 StartPage Expected Result: UI 流程完整,无中断 Evidence: .omo/evidence/task-9-ui-flow.pngCommit: YES (group with Tasks 8, 10)
- 编辑
-
10. StartUIPage.cs — 校验会话有效性
What to do:
- 编辑
Assets/Scripts/UI/StartPage/StartUIPage.cs TouchToStart()中改用LoginCacheManager.HasValidSession替代LoginCacheManager.HasCachedLogin- 添加可选的 Token 过期检测:
- JWT 本身包含过期时间(可解析 payload 中的 exp 字段)
- 如果 JWT 已过期 → 清除 session → 显示 LoginPage
- 简单方案: 暂不做 JWT 解码解析,只检查
HasValidSession
- 如有
RestoreInteraction()方法保持现有逻辑
Must NOT do:
- 不要修改不相关的 StartUIPage 逻辑
- 不要引入 JWT 解码库(暂不解码 JWT payload)
Recommended Agent Profile:
- Category:
visual-engineering - Skills: None
Parallelization:
- Can Run In Parallel: YES (with Tasks 8, 9)
- Parallel Group: Wave 4 (with Tasks 8, 9)
- Blocks: None
- Blocked By: Task 7
References:
Assets/Scripts/UI/StartPage/StartUIPage.cs— 当前文件Assets/Scripts/Online/Logic/LoginCacheManager.cs— 扩展后的缓存管理器(Task 6)
Acceptance Criteria:
TouchToStart()使用LoginCacheManager.HasValidSession判断- 有有效 session → 直接进 ChapterSelection
- 无有效 session → 显示 LoginPage
- Unity 编译通过
QA Scenarios:
Scenario: 有 JWT session 时跳过登录 Tool: Unity Editor Play Mode Preconditions: ES3 中存在有效 JWT 缓存 Steps: 1. 进入 MenuScene 2. 点击 TouchToStart Expected Result: 直接进入 ChapterSelection,不显示 LoginPage Evidence: .omo/evidence/task-10-skip-login.png Scenario: 无 JWT session 时显示登录 Preconditions: 清除 ES3 缓存 Steps: 1. 进入 MenuScene 2. 点击 TouchToStart Expected Result: LoginPage 显示 Evidence: .omo/evidence/task-10-show-login.pngCommit: YES (group with Tasks 8, 9)
- 编辑
Final Verification Wave
-
F1. Plan Compliance Audit —
oracleRead the plan end-to-end. For each "Must Have": verify implementation exists (read file, check compilation). For each "Must NOT Have": search codebase for forbidden patterns — reject with file:line if found. Check evidence files exist in .omo/evidence/. Compare deliverables against plan. Output:Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT -
F2. Code Quality Review —
unspecified-highCheck compilation status. Review changed files: proper async patterns (no sync-over-async), notry/catchswallowing, proper error handling, no magic strings (use constants), correct[Serializable]attributes on DTOs. Output:Build [PASS/FAIL] | Code Quality [N clean/N issues] | VERDICT -
F3. Real Manual QA —
unspecified-highStart from clean scene state. Execute QA scenarios from EVERY task — follow exact steps, capture evidence. Test integration flow: TapTap login → API call → JWT cache → restart → skip login. Test edge cases: network error, invalid credentials, ThirdParty.Unbound. Output:Scenarios [N/N pass] | Integration [N/N] | Edge Cases [N tested] | VERDICT -
F4. Scope Fidelity Check —
deepFor each task: read "What to do", read actual diff (git log/diff). Verify 1:1 — everything in spec was built (no missing), nothing beyond spec was built (no creep). Check "Must NOT do" compliance. Detect cross-task contamination. Output:Tasks [N/N compliant] | Contamination [CLEAN/N issues] | Unaccounted [CLEAN/N files] | VERDICT
Commit Strategy
- C1 (Task 1-4):
feat(online): add network models and asmdef references - C2 (Task 5-6):
feat(online): implement API client and extend login cache - C3 (Task 7):
feat(online): implement auth service with TapTap/password/register flows - C4 (Task 8-10):
feat(ui): integrate auth service into login UI
Success Criteria
Verification Commands
# In Unity Editor:
# 1. Open MenuScene
# 2. Enter Play Mode
# 3. Click TapTap Login button → should call POST /api/auth/third-party/login
# 4. Check Console for network request/response logs
# 5. Exit Play Mode → check ES3 cache contains JWT data
Final Checklist
- No compilation errors in IchniOnline.asmdef or dependent assemblies
- TapTap login → server API call → JWT → ES3 cache
- Password login (if server running) → JWT → ES3 cache
- Register (if server running) → user created
- LoginPage responds to all auth states (loading/success/failure)