Files
life-echo/skills/auth-login-register.md

63 lines
3.0 KiB
Markdown
Raw Normal View History

# 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 <access_token>` 解析 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 <access_token>`
- 收到 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 } }`,保证回到登录且无法返回。