hyapp-server/docs/google-login-integration.md
2026-04-30 02:30:32 +08:00

300 lines
8.6 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.

# 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/<firebase_project_id>` |
| `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/<firebase_project_id>`
- 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