300 lines
8.6 KiB
Markdown
300 lines
8.6 KiB
Markdown
# 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
|