Google 登录集成教程(Web + Expo 移动端)

本教程适用于 Next.js 后端 + Expo 移动端的 Google OAuth 登录集成。


一、Google Cloud Console 配置

1.1 创建项目

  1. 访问 Google Cloud Console
  2. 点击"新建项目",输入项目名称后创建

1.2 配置 OAuth 同意屏幕

⚠️ 重要:必须先配置同意屏幕,否则无法创建 OAuth 客户端 ID

  1. 进入 API 和服务OAuth 同意屏幕
  2. 点击 "Get started" 按钮
  3. 填写 App Information
    • App name:填写你的应用名称
    • User support email:选择你的邮箱
  4. 点击 "Next"
  5. Audience 页面直接点击 "Next"
  6. Contact Information 填写你的邮箱,点击 "Next"
  7. Finish 页面点击 "Create"
  8. 创建完成后,点击左侧 "Audience",添加测试用户(你的邮箱)

1.3 创建 OAuth 客户端 ID

⚠️ 关键 :需要创建 4 个不同的客户端 ID,分别用于 Web、Android、iOS 和 Expo Go 调试

进入 API 和服务凭据创建凭据OAuth 客户端 ID

A. Web 应用(后端用)
  • 应用类型:Web 应用

  • 已获授权的重定向 URI

    复制代码
    http://localhost:3000/api/auth/callback/google
    https://你的域名/api/auth/callback/google
  • 记录生成的 Client IDClient Secret,后续配置到后端环境变量

B. Android 客户端

⚠️ 最容易出错的地方:必须使用正确的 SHA-1 指纹,且必须开启自定义 URI scheme

  • 应用类型:Android

  • 包名 :填写你的 Android 包名(如 com.yourcompany.yourapp

  • SHA-1 证书指纹

    • Expo EAS Dashboard 获取 → 进入项目 → CredentialsAndroidUpload keystore → 复制 SHA-1 Fingerprint
    • 格式示例:42:DA:B6:72:B1:F1:0C:69:BA:13:73:E8:6E:8B:0B:F8:C0:A4:4C:6C

    ⚠️ 注意

    • 不要使用 debug.keystore 的指纹
    • 如果重新生成 keystore,必须更新这里的指纹
  • 创建后必须执行

    1. 点击刚创建的 Android 客户端
    2. 点击 Advanced settings
    3. 开启 Enable custom URI scheme

    ⚠️ 必须开启 :否则会报错 Custom URI scheme is not enabled for your Android client

  • 记录生成的 Client ID

C. iOS 客户端(如需要)
  • 应用类型:iOS
  • Bundle ID :填写你的 iOS Bundle ID(如 com.yourcompany.yourapp
  • 记录生成的 Client ID
D. Expo Web / Proxy(仅用于 Expo Go 调试)
  • 应用类型:Web 应用

  • 已获授权的重定向 URI

    复制代码
    https://auth.expo.io/@你的expo用户名/你的项目slug

    💡 提示:在 app.json 中查看 ownerslug 字段

  • 记录生成的 Client IDClient Secret


二、后端配置

2.1 环境变量配置

在后端项目的 .env 文件中添加:

env 复制代码
# Web 应用凭据
GOOGLE_CLIENT_ID=你的Web客户端ID
GOOGLE_CLIENT_SECRET=你的Web客户端Secret

# 移动端客户端 ID(用于验证 token)
GOOGLE_ANDROID_CLIENT_ID=你的Android客户端ID
GOOGLE_IOS_CLIENT_ID=你的iOS客户端ID
GOOGLE_EXPO_CLIENT_ID=你的Expo客户端ID

2.2 生产环境配置

如果使用 Vercel 部署:

  1. 进入项目设置 → Environment Variables
  2. 添加上述所有环境变量

三、移动端配置

3.1 环境变量配置

在移动端项目的 .env 文件中添加:

env 复制代码
EXPO_PUBLIC_API_URL=http://10.0.2.2:3000
EXPO_PUBLIC_GOOGLE_ANDROID_CLIENT_ID="你的Android客户端ID"
EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID="你的iOS客户端ID"
EXPO_PUBLIC_GOOGLE_EXPO_CLIENT_ID="你的Expo客户端ID"
EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID="你的Expo客户端ID"

💡 提示:10.0.2.2 是 Android 模拟器访问本机的地址

3.2 app.json 配置

⚠️ 关键配置:必须正确配置 intentFilters,否则 Google 回调无法返回 App

json 复制代码
{
  "expo": {
    "scheme": "yourappscheme",
    "android": {
      "package": "com.yourcompany.yourapp",
      "intentFilters": [
        {
          "action": "VIEW",
          "category": ["BROWSABLE", "DEFAULT"],
          "data": [
            {
              "scheme": "com.googleusercontent.apps.你的Android客户端ID的数字部分",
              "path": "/oauth2redirect"
            }
          ]
        }
      ]
    }
  }
}

💡 提示:scheme 的格式为 com.googleusercontent.apps. + Android Client ID 的数字部分(去掉 .apps.googleusercontent.com

3.3 登录页面代码

app/(auth)/sign-in.tsx 中:

typescript 复制代码
import * as Google from "expo-auth-session/providers/google";
import { makeRedirectUri, ResponseType } from "expo-auth-session";
import Constants from "expo-constants";

// 判断是否在 Expo Go 环境
const isExpoGo = Constants.appOwnership === "expo";

// 配置 redirectUri
const redirectUri = useMemo(() => {
  if (isExpoGo) {
    // Expo Go 环境使用代理
    return makeRedirectUri({ useProxy: true, path: "oauthredirect" });
  }
  // Development Build / 正式包使用自定义 scheme
  const googleScheme = "com.googleusercontent.apps.你的Android客户端ID的数字部分";
  return makeRedirectUri({
    scheme: googleScheme,
    path: "oauth2redirect",
    native: `${googleScheme}:/oauth2redirect`
  });
}, [isExpoGo]);

// 配置 Google 登录
const [googleRequest, googleResponse, promptGoogleSignIn] = Google.useAuthRequest({
  expoClientId: isExpoGo ? expoClientId ?? undefined : undefined,
  androidClientId: Platform.OS === "android" ? androidClientId ?? undefined : undefined,
  iosClientId: Platform.OS === "ios" ? iosClientId ?? undefined : undefined,
  webClientId: webClientId ?? undefined,
  responseType: ResponseType.Code,
  usePKCE: true,
  shouldAutoExchangeCode: false,
  redirectUri,
  scopes: ["openid", "email", "profile"]
});

// 处理登录响应
useEffect(() => {
  if (googleResponse?.type === "success") {
    const { code, codeVerifier } = googleResponse.params;
    // 发送到后端验证
    // ...
  }
}, [googleResponse]);

3.4 创建回调路由

⚠️ 必须创建:否则回调会落在 Unmatched Route 页面

创建 app/oauth2redirect.tsx

typescript 复制代码
import { useEffect } from "react";
import * as WebBrowser from "expo-web-browser";

export default function OAuthRedirectScreen() {
  useEffect(() => {
    WebBrowser.maybeCompleteAuthSession();
  }, []);

  return null;
}

四、构建与验证

⚠️ 重要:Expo Go 无法测试 Google 登录,必须使用 Development Build

4.1 为什么需要 Development Build?

Expo Go 的回调 URL(exp://...)会被 Google Console 拒绝,因此必须构建真实的 APK/IPA 才能测试。

4.2 构建流程

  1. 生成 Development Build

    bash 复制代码
    eas build --profile development --platform android

    ⏱️ 构建时间约 20 分钟,请耐心等待

  2. 删除旧版本 App

    ⚠️ 必须删除:否则新的 intentFilters 不会生效

    在手机上卸载旧版本的 App

  3. 安装新构建的 APK

    从 EAS Dashboard 下载 APK 并安装到手机

  4. 启动开发服务器

    bash 复制代码
    npx expo start --dev-client

4.3 验证配置

验证回调是否注册成功
bash 复制代码
adb shell cmd package resolve-activity \
  -d "com.googleusercontent.apps.你的Android客户端ID的数字部分:/oauth2redirect" \
  -a android.intent.action.VIEW

预期输出 :应包含你的包名和 .MainActivity,例如:

复制代码
com.yourcompany.yourapp/.MainActivity

如果未找到:说明安装的仍是旧 APK,请重新卸载并安装新版本

验证 APK 签名(可选)
bash 复制代码
$ANDROID_HOME/build-tools/36.0.0/apksigner verify --print-certs dev-client.apk

检查SHA-1 digest 应与 Google Console 中登记的一致


五、授权流程说明

  1. 客户端使用 expo-auth-session/providers/google 发起授权请求(responseType=code,PKCE 自动开启)
  2. 用户在浏览器中选择 Google 账号
  3. Google 重定向到自定义 scheme:
    • Development Build:com.googleusercontent.apps.xxx:/oauth2redirect
    • Expo Go:https://auth.expo.io/...
  4. 客户端获取 authorizationCodecodeVerifier
  5. 客户端将 code 和 verifier 发送给后端
  6. 后端使用对应的 Client ID 向 Google 交换 id_token
  7. 后端验证 token 并创建会话

💡 提示:授权完成后浏览器不会自动关闭,可手动返回 App。关键是确认终端日志打印 Google auth response success


六、常见问题排查

现象 原因 解决方案
400 错误:redirect_uriexp://... 仍在 Expo Go 环境 使用 Development Build
400 错误:Custom URI scheme is not enabled Android 客户端未开启自定义 URI 在 Google Console 中开启 Enable custom URI scheme
浏览器完成登录但无回调 intentFilters 未注册 使用 adb resolve-activity 检查;重新安装 Dev Client
后端交换 token 失败 环境变量缺失或错误 检查 GOOGLE_*_CLIENT_ID 是否齐全且正确
SHA-1 指纹不匹配 使用了错误的 keystore 从 EAS Dashboard 获取正确的 SHA-1 并更新到 Google Console

七、重要提醒

  1. Keystore 管理:如果重新生成 keystore,必须同步更新 Google Console 中的 SHA-1 指纹
  2. 环境变量同步:后端和移动端的 Client ID 必须一一对应
  3. 测试用户:开发阶段记得在 OAuth 同意屏幕中添加测试用户
  4. 回调验证 :每次重新构建后,务必使用 adb resolve-activity 验证回调是否注册成功

八、调试技巧

  1. 查看终端日志 :确认是否打印 Google auth response success
  2. 检查 redirectUri :在代码中打印 redirectUri 确认格式正确
  3. 验证 Client ID :确认传递给 useAuthRequest 的 Client ID 与平台匹配
  4. 测试回调 :使用 adb shell am start 手动触发回调测试

完成以上配置后,即可实现 Web 端和移动端的 Google 登录功能。

相关推荐
Nan_Shu_61413 分钟前
学习: Threejs (2)
前端·javascript·学习
G_G#21 分钟前
纯前端js插件实现同一浏览器控制只允许打开一个标签,处理session变更问题
前端·javascript·浏览器标签页通信·只允许一个标签页
@大迁世界37 分钟前
TypeScript 的本质并非类型,而是信任
开发语言·前端·javascript·typescript·ecmascript
GIS之路1 小时前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug1 小时前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu121381 小时前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中1 小时前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路1 小时前
GDAL 实现矢量合并
前端
hxjhnct1 小时前
React useContext的缺陷
前端·react.js·前端框架
前端 贾公子2 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端