# Firebase Google 登录接入流程 本文档对应当前 Flutter Android 测试 App 和后端登录契约。Google 登录由 Firebase Auth 承接;后端不接收 Google account id,不把 Google 资料字段当身份凭证,只接收 Firebase ID token。 当前目标包名: ```text com.org.laluparty ``` ## 当前项目状态 已接入: - Android `applicationId`: `com.org.laluparty` - Android `namespace`: `com.org.laluparty` - Firebase Android App 配置文件:`android/app/google-services.json` - Firebase Authentication Google Sign-In - `google_sign_in`: `7.2.0` - `google_sign_in_android`: `7.2.10` - `android/settings.gradle.kts` 已声明 `com.google.gms.google-services` - `android/app/build.gradle.kts` 已应用 `com.google.gms.google-services` 当前 `google-services.json` 包含: ```text package_name: com.org.laluparty web client_id: 821303287694-o0g9nugq6fglssugri1ls4auud549rll.apps.googleusercontent.com ``` ## Firebase 控制台配置 1. 进入 Firebase Console,选择项目。 2. 添加 Android App。 Android package name 填: ```text com.org.laluparty ``` 3. 添加 debug 证书指纹。 当前本机 debug keystore: ```text SHA1: C2:F0:20:54:81:57:F4:D1:55:1E:21:98:08:22:69:E1:F6:4A:92:CA SHA-256: F5:91:FC:90:F8:17:26:24:67:2E:FF:77:AA:AE:12:42:21:B4:A8:50:E2:E3:00:B8:BE:DE:B7:D3:1E:0A:D2:28 ``` 重新查询命令: ```bash cd /Users/zuozuo/Desktop/HY/hyapp-flutter/android ./gradlew signingReport ``` 4. 启用 Google 登录。 Firebase Console: ```text Authentication -> Sign-in method -> Google -> Enable ``` 需要选择项目支持邮箱。 5. 重新下载 `google-services.json`。 添加 SHA 指纹或启用 Google 登录后,都建议重新下载一次。 放置路径: ```text /Users/zuozuo/Desktop/HY/hyapp-flutter/android/app/google-services.json ``` 6. 确认 `google-services.json` 里有 Web OAuth Client。 检查命令: ```bash jq -r '.client[] | .client_info.android_client_info.package_name as $pkg | [$pkg, (.oauth_client[]? | select(.client_type==3) | .client_id)] | @tsv' android/app/google-services.json ``` 必须能看到 `client_type: 3` 对应的 Web client id。`google_sign_in_android` 会用它做 Android 登录配置。 ## Google Cloud 侧配置 Firebase 通常会自动创建 OAuth 客户端。需要确认: - Android OAuth client 的包名是 `com.org.laluparty` - Android OAuth client 里有当前 debug SHA1 - Web OAuth client 存在 - OAuth consent screen 已配置 如果以后要调用 People API、Drive API 等 Google API,再去 Google Cloud API Library 单独启用;当前只做登录不需要额外 API。 ## Flutter 代码接入 当前登录入口: ```text lib/src/pages/login_page.dart ``` Google 登录封装: ```text lib/src/google_auth_service.dart ``` 当前初始化方式: ```dart GoogleSignIn.instance.initialize( clientId: AppConfig.googleClientId, serverClientId: AppConfig.googleServerClientId, ); ``` Android 已接入 `google-services.json` 时,可以不传 `GOOGLE_SERVER_CLIENT_ID`。如果不使用 `google-services.json`,运行时必须传 Web client id: ```bash flutter run -d emulator-5554 \ --dart-define=GOOGLE_SERVER_CLIENT_ID=你的Web客户端ID ``` ## 后端登录请求 Flutter 侧必须先完成 Firebase Auth 登录,再从 Firebase 当前用户获取 ID token。后端登录只认 Firebase ID token: ```text POST /api/v1/auth/third-party/login ``` 请求字段: ```json { "provider": "firebase", "credential": "Firebase ID token", "username": "optional Firebase display name snapshot", "avatar": "optional Firebase photo url snapshot", "device_id": "local device id", "device": "flutter-android", "source": "hyapp-flutter", "platform": "android" } ``` `username/avatar` 在这个接口里只允许作为 Firebase 当次返回的资料快照,不代表注册完成。注册页的权威提交入口仍然是: ```text POST /api/v1/users/me/onboarding/complete ``` 注册页只提交用户主动确认的 `username/avatar/country`。`device_id/platform/device/source` 是客户端自动上报的注册上下文,不需要用户填写。 ## 后端校验规则 后端 `user-service` 必须使用 Firebase verifier 校验 ID token。`StaticThirdPartyVerifier` 只能用于单元测试或显式 mock provider,不能用于 `provider=firebase`: | Item | Rule | | --- | --- | | `provider` | 固定传 `firebase`,并出现在 user-service allowlist | | `credential` | Firebase Auth 当前用户的 ID token,不能是 Google account id、email 或 access token | | `provider_subject` | 从校验后的 Firebase token `sub`/`uid` 提取,作为 `third_party_identities(provider, provider_subject)` 的绑定主键 | | `iss` | 必须是 `https://securetoken.google.com/` | | `aud` | 必须等于后端配置的 Firebase project id | | `signature` | 使用 Firebase Admin SDK 或 Firebase 公钥校验,不能跳过签名 | | `firebase.sign_in_provider` | 首版 Google 登录必须等于 `google.com`;后续支持 Apple/phone 时改成配置 allowlist | | `email/name/picture` | 只作为资料快照辅助字段,不能作为登录绑定主键 | Firebase ID token、Google access token、provider 原始 credential 都不能写入日志、审计表或数据库。gateway 只负责 HTTP JSON 到 gRPC 的转发和 `request_id` 透传,不保存 Firebase service account。 ## Android 运行验证 启动 Google 手机模拟器: ```bash /Users/zuozuo/Library/Android/sdk/emulator/emulator -avd Pixel_8_API_35 ``` 确认设备在线: ```bash adb devices -l ``` 运行 App: ```bash cd /Users/zuozuo/Desktop/HY/hyapp-flutter flutter run -d emulator-5554 ``` Android 模拟器访问本机后端默认地址: ```text http://10.0.2.2:13000 ``` 如果要指定后端地址: ```bash flutter run -d emulator-5554 \ --dart-define=API_BASE_URL=http://10.0.2.2:13000 ``` 如果旧包名已经安装过,可以卸载旧包: ```bash adb uninstall com.hyapp.hyapp_flutter adb uninstall com.org.laluparty ``` 然后重新运行: ```bash flutter run -d emulator-5554 ``` ## Release 前必须补充 当前 release 还临时使用 debug signing config。正式包必须: 1. 创建 release keystore。 2. 配置 Android release signing。 3. 用 release keystore 跑: ```bash cd /Users/zuozuo/Desktop/HY/hyapp-flutter/android ./gradlew signingReport ``` 4. 把 release SHA1 和 SHA-256 添加到 Firebase Android App。 5. 重新下载并替换 `android/app/google-services.json`。 6. 如果上架 Google Play,还要把 Play Console 的 App signing key SHA1/SHA-256 添加到 Firebase。 ## 常见错误 ### 选择账号后直接取消 常见原因: - Firebase 包名不是 `com.org.laluparty` - SHA1 没添加或添加错了 - `google-services.json` 不是最新文件 - `google-services.json` 没放在 `android/app/` - 没有 Web OAuth client ### serverClientId must be provided on Android 说明 Android 没从 `google-services.json` 读到 Web client id。 处理: 1. 确认 `android/app/google-services.json` 存在。 2. 确认 Gradle 已应用 `com.google.gms.google-services`。 3. 确认 JSON 内有 `client_type: 3` 的 OAuth client。 4. 重新下载 Firebase 配置文件。 5. 或运行时传: ```bash --dart-define=GOOGLE_SERVER_CLIENT_ID=你的Web客户端ID ``` ### DEVELOPER_ERROR / clientConfigurationError 常见原因: - 包名不匹配 - SHA 指纹不匹配 - 使用了错误 Firebase 项目的 `google-services.json` - Android OAuth client 和 Web OAuth client 配置不完整 ### 后端返回 AUTH_FAILED 后端要求: - `provider` 必须在允许列表里,当前 Firebase 登录应包含 `firebase` - `credential` 必须是未过期的 Firebase ID token - `device_id` 不能为空 - Firebase project id 必须和 token 的 `aud` 一致 - token issuer 必须匹配 `https://securetoken.google.com/` - token 签名必须能通过 Firebase Admin SDK 或 Firebase 公钥校验 - `firebase.sign_in_provider` 必须在后端 allowlist 中,首版 Google 登录为 `google.com` 如果 Firebase 登录成功但后端失败,优先用响应 `request_id` 查 gateway/user-service 日志。日志只能记录失败类型和 Firebase UID 摘要,不能记录原始 ID token。 ## 参考 - Firebase Android setup: https://firebase.google.com/docs/android/setup - Firebase Android Google Sign-In: https://firebase.google.com/docs/auth/android/google-signin - Firebase verify ID tokens: https://firebase.google.com/docs/auth/admin/verify-id-tokens - google_sign_in: https://pub.dev/packages/google_sign_in - google_sign_in_android integration: https://pub.dev/packages/google_sign_in_android