Files
life-echo/skills/auth-login-register.md
iammm0 6526c08c3a docs: 新增技能文档
- 新增Skills.md技能说明
- 新增skills/技能文档目录

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-03 11:30:12 +08:00

63 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 } }`,保证回到登录且无法返回。