# Skill:登录与注册机制 与具体业务无关的认证设计:服务端 API 与客户端 Android 的登录、注册、令牌与鉴权约定。 --- ## 服务端(API) ### 认证方式 - **访问令牌(Access Token)**:JWT,用于接口鉴权,默认有效期 2 小时(`ACCESS_TOKEN_EXPIRE_MINUTES`)。 - **刷新令牌(Refresh Token)**:随机字符串,存库,默认 30 天有效;用于在访问令牌过期后换取新访问令牌。 ### 密码 - 使用 **bcrypt** 哈希存储,不存明文。 - 注册/登录时由 `auth_service.hash_password` / `verify_password` 处理。 ### 登录/注册入口 - 手机号 + 密码:`POST /api/auth/login`、`POST /api/auth/register`。 - 手机号 + 短信验证码:`POST /api/auth/login/sms`(未注册则自动注册,需提供昵称)。 - 所有入口均要求请求体中 `agreed_to_terms == true`,否则 400。 ### 令牌刷新 - `POST /api/auth/refresh`,Body: `{ "refresh_token": "..." }`。 - 校验:存在、未撤销、未过期、对应用户存在;通过后返回新的 `access_token`,`refresh_token` 原样返回(不轮换)。 ### 鉴权依赖 - 需要登录的接口:`Depends(get_current_user)`,从 `Authorization: Bearer ` 解析 JWT,校验 `type == "access"` 并加载用户。 - 可选登录:`Depends(get_optional_user)`,无 token 或无效时返回 `None`。 ### 路由与安全 - 认证相关路由统一前缀:`/api/auth`(如 login、register、refresh、logout 等)。 - OAuth2 约定:`OAuth2PasswordBearer(tokenUrl="/api/auth/login")`,仅用于声明从哪里取 token,实际登录仍用上述接口。 --- ## 客户端(Android) ### 令牌存储 - 使用 **DataStore Preferences**(`TokenPreferences`)存 `access_token`、`refresh_token`、`user_id`。 - 通过单例 **TokenManager** 读写;提供 `initialize(context)`、`saveTokens`、`getAccessToken`/`getRefreshToken`(含 suspend 与 sync 版本)、`clearTokens`。 ### 登录状态 - TokenManager 维护 `isLoggedIn`(有有效 access_token 即为 true),并提供 `rememberIsLoggedIn()` 供 Compose 使用。 - 登出或刷新失败时调用 `clearTokens()` 并 `notifyTokenRefreshFailed()`,由回调统一处理(如清栈并跳转登录页)。 ### 请求头与刷新 - 使用 **AuthInterceptor**(Ktor Client 插件):请求前自动附加 `Authorization: Bearer `。 - 收到 401 时:用当前 refresh_token 调 `AuthService.refreshToken()`;成功则写回新 token,失败则 `clearTokens()` + `notifyTokenRefreshFailed()`,由 App 层跳转登录。 ### 登录成功/登出与导航 - 登录成功:由各登录入口回调 `onLoginSuccess`,主流程将 `isLoggedIn = true` 并导航到主界面(如会话列表),并 `popUpTo(Login)` 清掉登录页。 - 登出或刷新失败:`onLogout` / TokenManager 回调中执行 `navController.navigate(Screen.Login.route) { popUpTo(0) { inclusive = true } }`,保证回到登录且无法返回。