身份认证
电子邮件认证、OTP 回调、Google 登录、会话和账号操作。
模板用一个轻量 repository 层、SessionController 和 Compose 页面包装
Supabase Auth,覆盖邮箱认证、OTP 验证、密码恢复、Google 登录和账号安全操作。
提供什么
| 功能 | 状态 | 实现 |
|---|---|---|
| 邮箱/密码登录 | Integrated | SupabaseAuthRemoteDataSource.signIn() + Supabase Email provider |
| 注册 + OTP 验证 | Integrated | signUp()、verifyEmailOtp()、resendEmailOtp() |
| 忘记/重置密码 | Integrated | resetPasswordForEmail()、recovery OTP、然后 updateUser { password = ... } |
| 修改邮箱 | Integrated | updateUser { email = ... },再验证 email-change OTP |
| 修改密码 | Integrated | updateUser { password = ... } |
| 登出其他会话 | Integrated | auth.signOut(SignOutScope.OTHERS) |
| Google 登录 | Integrated | Android Credential Manager -> Google ID token -> Supabase ID-token 登录 |
| 删除账号 | Partial | 仅客户端清理部分数据并本地登出;见下面的诚实说明 |
关键文件
会话状态
SupabaseClientProvider 安装 Auth 插件时使用:
install(Auth) {
scheme = "soar"
host = "auth-callback"
}因此 Supabase Auth 必须 allow-list soar://auth-callback。SessionController
监听 supabaseClient.auth.sessionStatus,把 SessionStatus.Authenticated
映射成 UserInfo?,并以应用级作用域暴露 currentUser 和 isLoading
这两个 eager StateFlow。
应用代码不会手写 token 持久化逻辑,而是使用 Supabase Android Auth 插件的
SettingsSessionManager,底层是 multiplatform Settings API。启动时会调用
auth.awaitInitialization(),让 auth gate 等待恢复后的会话状态。
邮箱流程
认证页面使用 feature/auth/validation/ 中的纯 Kotlin validator:
validateEmail()要求非空且格式像邮箱。validatePassword()要求至少 8 位,并同时包含字母和数字。validatePasswordConfirmation()校验确认密码。validateOtp()要求 6 位数字验证码。
AuthRepository 把 Supabase 调用包装成 AppResult<Unit>。登录、注册、OTP
验证、修改密码和完成密码重置只尝试一次;重发 OTP、请求重置密码、修改邮箱、
登出其他会话和当前删除账号流程会按幂等操作处理,最多重试 3 次,每次间隔
250 ms。
Google 登录
只有设置这个 key 后才会显示 Google 登录:
GOOGLE_WEB_CLIENT_ID=your_google_oauth_web_client_id这里要使用 Google Cloud Console 中的 OAuth Web client ID,不是 Android
client ID。CredentialManagerGoogleSignInController 会创建
GetGoogleIdOption,把这个 web client ID 设置为 server client ID,加入
SHA-256 nonce,并返回 Google ID token 和原始 nonce。
SupabaseAuthRemoteDataSource.signInWithGoogle() 再通过 Supabase 的
IDToken provider、provider = Google 完成登录。
Credential Manager 的结果会被明确处理:
| 结果 | 应用行为 |
|---|---|
Success(idToken, rawNonce) | 通过 Supabase 登录 |
Cancelled | 当作无操作 |
NoCredential | 提示设备上没有可用 Google 账号 |
Failure(message) | 显示映射后的失败信息 |
同时在 Supabase Auth 中启用 Google provider,并保留同一个回调:
soar://auth-callback账号安全操作
AccountSecurityViewModel 驱动账号安全页面,可以:
- 请求修改邮箱,并验证发送到新邮箱的 OTP。
- 修改当前密码。
- 使用
SignOutScope.OTHERS登出其他会话。 - 触发当前删除账号流程。
删除账号的诚实说明
Kotlin 模板当前没有提供 delete-account Edge Function。
SupabaseAuthRemoteDataSource.deleteAccount() 不会删除 auth.users 行。
当前实现是客户端流程:
- 读取当前 Supabase user id。
- 删除该用户的
public.todos行。 - 更新同 id 的
public.profiles,把full_name、bio、phone、location、avatar_url设置为null。 - 调用
auth.signOut(SignOutScope.LOCAL)。
这样会清掉本地登录态和部分用户数据,但 Supabase Auth 用户仍然存在。
sample-uploads/<user-id>/ 下的存储对象不会清理,device token 和 billing 行
也没有被这个客户端流程显式删除。
建议作为模板修复:把 Swift/Expo 模板中的 delete-account Edge Function
移植到 Kotlin 模板。service-role 函数可以校验调用者 JWT,删除用户数据和
Storage 对象,再调用 auth.admin.deleteUser(userId)。这也关系到 Google Play
的账号删除政策。
验证
- 使用邮箱/密码注册并完成 6 位 OTP。
- 登出后再用邮箱/密码登录。
- 发起密码恢复并完成 recovery OTP 流程。
- 添加
GOOGLE_WEB_CLIENT_ID、启用 Supabase Google Auth、重新构建,并确认 Google 按钮出现。 - 在 Account Security 中修改邮箱和密码。
- 在模板修复前,确认删除账号行为与本页描述完全一致。
