跳过内容

Supabase Google 登录 - 通用设置

本指南将指导您如何使用 Capacitor 社交登录插件将 Google Sign-In 与 Supabase 身份验证集成。这种设置允许您在移动平台上使用本机 Google Sign-In,同时利用 Supabase Auth 进行后端身份验证。

在开始之前,请确保您已经:

  1. 创建了一个 Supabase 项目

  2. 阅读指南 Google 登录通用设置 了解如何设置 Google OAuth 凭证

  3. 按照以下步骤设置 Google OAuth 凭证,具体步骤请参见各个平台的指南:

在 Supabase 中启用 Google OAuth 提供者

标题:在 Supabase 中启用 Google OAuth 提供者
  1. 前往您的 Supabase 控制台

  2. 点击您的

    Supabase 项目选择器
  3. 前往 Authentication 菜单

    Supabase 身份验证菜单
  4. 点击 Providers 选项卡

    Supabase 提供商选项卡
  5. 找到 Google 提供商

    Supabase Google Provider
  6. 启用提供者

    Supabase Google Provider Enable
  7. 添加您计划使用的平台的客户端 ID

    Supabase Google Provider Add Client IDs
  8. 点击 Save button

    Supabase Google Provider Save

Voilà,您现在已经启用了 Supabase 身份验证的 Google Sign-In 🎉

完整的实现

实现生成遵循 Supabase 随机数要求:

// Generate URL-safe random nonce
function getUrlSafeNonce(): string {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join('');
}
// Hash the nonce with SHA-256
async function sha256Hash(message: string): Promise<string> {
const encoder = new TextEncoder();
const data = encoder.encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
}
// Generate nonce pair
async function getNonce(): Promise<{ rawNonce: string; nonceDigest: string }> {
const rawNonce = getUrlSafeNonce();
const nonceDigest = await sha256Hash(rawNonce);
return { rawNonce, nonceDigest };
}

流程:

  • rawNonce: URL 安全的随机字符串(64 个十六进制字符)
  • nonceDigest: SHA-256 散列值 rawNonce (hex-encoded)
  • nonceDigest 会被传递给 Google Sign-In → Google 将 nonce digest 包含在 ID token 中
  • rawNonce 会被传递给 Supabase → Supabase 会将 raw nonce 哈希并与 token 的 nonce 进行比较

该函数初始化插件并使用 Google 进行登录:

await SocialLogin.initialize({
google: {
webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
// iOS only:
iOSClientId: 'YOUR_IOS_CLIENT_ID.apps.googleusercontent.com',
mode: 'online', // Required to get idToken
},
});
const response = await SocialLogin.login({
provider: 'google',
options: {
scopes: ['email', 'profile'],
nonce: nonceDigest, // Pass the SHA-256 hashed nonce
},
});

3. JWT Validation

第 3 步:JWT 验证

在将令牌发送到 Supabase 之前,实现验证 JWT 令牌:

function validateJWTToken(idToken: string, expectedNonceDigest: string): { valid: boolean; error?: string } {
const decodedToken = decodeJWT(idToken);
// Check audience matches your Google Client IDs
const audience = decodedToken.aud;
if (!VALID_GOOGLE_CLIENT_IDS.includes(audience)) {
return { valid: false, error: 'Invalid audience' };
}
// Check nonce matches
const tokenNonce = decodedToken.nonce;
if (tokenNonce && tokenNonce !== expectedNonceDigest) {
return { valid: false, error: 'Nonce mismatch' };
}
return { valid: true };
}

为什么在 Supabase 之前验证?

在将令牌发送到 Supabase 之前,验证 JWT 令牌具有多个重要目的:

  1. 防止非法请求: 如果令牌的受众或 nonce 不匹配,Supabase 将拒绝令牌。验证令牌之前避免了不必要的 API 调用并提供了更清晰的错误消息。

  2. 令牌缓存问题: 在某些平台(尤其是 iOS)上,Google Sign-In SDK 可以缓存令牌以提高性能。当返回缓存令牌时,缓存令牌可能已使用不同的 nonce(或无 nonce)生成,导致 Supabase 拒绝令牌并显示“nonce 不匹配”错误。通过在发送到 Supabase 之前验证令牌,我们可以尽早检测到此问题并自动重试使用新令牌。

  3. 安全 (iOS): 在 iOS 上,验证确保令牌是为您的特定 Google Client IDs 发行的,防止使用其他应用程序的令牌引起的潜在安全问题。

  4. 更好的错误处理: 在 Supabase 允许之前检测到问题,可以自动重试逻辑,这对于透明地处理 iOS 缓存问题至关重要。

如果验证失败,函数将自动:

  1. 从 Google 登出(清除缓存令牌 - iOS 上至关重要)
  2. 重试一次身份验证(强制使用新令牌生成并使用正确的 nonce)
  3. 如果重试也失败,返回错误

4. Supabase 登录

标题:4. Supabase 登录

最后,经过验证的令牌被发送到 Supabase:

const { data, error } = await supabase.auth.signInWithIdToken({
provider: 'google',
token: googleResponse.idToken,
nonce: rawNonce, // Pass the raw (unhashed) nonce
});

完成 Code 参考

标题:完成 Code 参考

完整的实现可在 示例应用的 supabaseAuthUtils.ts 文件中找到,文件包含:

  • getUrlSafeNonce() - 生成 URL 安全的随机非对称性
  • sha256Hash() - 使用 SHA-256 对字符串进行散列
  • getNonce() - 生成随机数对
  • decodeJWT() - 解码 JWT token
  • validateJWTToken() - 验证 JWT 观众和随机数
  • authenticateWithGoogleSupabase() - 主要认证函数,自动重试

附加示例文件

标题:附加示例文件

请按照您的目标平台进行平台特定的设置指南: