# Firebase Google 登录接入流程

本文档对应当前 Flutter Android 测试 App 和后端登录契约。Google 登录由 Firebase Auth 承接；后端不接收 Google account id，不把 Google 资料字段当身份凭证，只接收 Firebase ID token。

当前目标包名：

```text
com.org.laluparty
```

后端 App 映射：

```text
com.org.laluparty -> app_code lalu
```

客户端登录请求必须能让 gateway 解析到 `lalu`：可以带包名和 `platform=android`，也可以带 `X-App-Code: lalu`。后端会把 `app_code` 写入登录 token，后续刷新 token、房间、钱包和用户资料请求都在同一个 App 作用域内执行。

## 当前项目状态

已接入：

- 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(app_code, 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
