跳过内容

Facebook 登录设置

GitHub

简介

简介

In this guide, you will learn how to setup Facebook Login with Capgo Social Login. You will need the following:

  • Facebook开发者帐户
  • 您的应用程序的包名/捆绑ID
  • 访问终端以生成密钥哈希(Android)

创建Facebook应用

  1. 遵循教程

    创建应用 Create a Facebook App

  2. 为您的应用程序添加 Facebook 登录

    在您的 Facebook 开发者控制台中,添加 Facebook 登录产品到您的应用程序

  3. 在发布您的应用程序到公众之前,遵循以下步骤 教程 发布它

这是您需要进行集成的关键信息的位置:

  1. CLIENT_TOKEN:

    Facebook 开发者控制台显示客户端令牌的位置
  2. APP_ID:

    Facebook 开发者控制台显示应用程序 ID 的位置
  3. APP_NAME:

    Facebook 开发者控制台显示应用程序名称的位置

Android 配置

Android 设备设置
  1. 为您的应用添加网络权限 AndroidManifest.xml

    确保以下行存在:

    <uses-permission android:name="android.permission.INTERNET"/>
  2. 生成 Android 密钥哈希

    这是 Facebook 需要的关键安全步骤。打开您的终端并运行:

    终端窗口
    keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64 -A

    当提示输入密码时,请使用: android

  3. 在 Facebook 应用中添加密钥哈希

    1. 前往 Facebook Developers 中的应用仪表板
    2. 导航到设置 > 基本
    3. 滚动到“Android”部分
    4. 如果 Android 没有添加,请点击“添加平台”,并填写详细信息
    5. 添加您生成的密钥哈希
    6. 在生产环境中,添加 debug 和 release 密钥哈希
  4. 更新您的 AndroidManifest.xml 以包含:

    <application>
    ...
    <activity android:name="com.facebook.FacebookActivity"
    android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
    android:label="@string/app_name" />
    <activity
    android:name="com.facebook.CustomTabActivity"
    android:exported="true">
    <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="FB[APP_ID]" />
    </intent-filter>
    </activity>
    </application>
  1. 在Facebook开发者控制台中添加iOS平台

    1. 前往您的应用程序的Facebook开发者控制台
    2. 导航到设置>基本
    3. 滚动到页面底部并点击“添加平台”
    4. 选择iOS并填写所需详细信息
  2. 打开你的 Xcode 项目并导航到 Info.plist

  3. 在 Info.plist 中添加以下条目:

    <key>FacebookAppID</key>
    <string>[APP-ID]</string>
    <key>FacebookClientToken</key>
    <string>[CLIENT-TOKEN]</string>
    <key>FacebookDisplayName</key>
    <string>[APP-NAME]</string>
    <key>LSApplicationQueriesSchemes</key>
    <array>
    <string>fbapi</string>
    <string>fb-messenger-share-api</string>
    </array>
    <key>CFBundleURLTypes</key>
    <array>
    <dict>
    <key>CFBundleURLSchemes</key>
    <array>
    <string>fb[APP-ID]</string>
    </array>
    </dict>
    </array>
  4. 修改 AppDelegate.swift

    import FBSDKCoreKit
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    // Initialize Facebook SDK
    FBSDKCoreKit.ApplicationDelegate.shared.application(
    application,
    didFinishLaunchingWithOptions: launchOptions
    )
    return true
    }
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
    // Called when the app was launched with a url. Feel free to add additional processing here,
    // but if you want the App API to support tracking app url opens, make sure to keep this call
    if (FBSDKCoreKit.ApplicationDelegate.shared.application(
    app,
    open: url,
    sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
    annotation: options[UIApplication.OpenURLOptionsKey.annotation]
    )) {
    return true;
    } else {
    return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
    }
    }
    }

在你的应用中使用 Facebook 登录

在您的应用程序中使用Facebook登录
  1. 在您的应用程序中初始化Facebook登录

    import { SocialLogin } from '@capgo/capacitor-social-login';
    // Initialize during app startup
    await SocialLogin.initialize({
    facebook: {
    appId: 'APP_ID',
    clientToken: 'CLIENT_TOKEN',
    }
    })
  2. 实现登录功能

    async function loginWithFacebook() {
    try {
    const result = await SocialLogin.login({
    provider: 'facebook',
    options: {
    permissions: ['email', 'public_profile'],
    limitedLogin: false // See Limited Login section below for important details
    }
    });
    console.log('Facebook login result:', result);
    // Handle successful login
    } catch (error) {
    console.error('Facebook login error:', error);
    // Handle error
    }
    }
  3. 获取用户资料

    登录成功后,您可以获取更多的资料信息:

    async function getFacebookProfile() {
    try {
    const profileResponse = await SocialLogin.providerSpecificCall({
    call: 'facebook#getProfile',
    options: {
    fields: ['id', 'name', 'email', 'first_name', 'last_name', 'picture']
    }
    });
    console.log('Facebook profile:', profileResponse.profile);
    return profileResponse.profile;
    } catch (error) {
    console.error('Failed to get Facebook profile:', error);
    return null;
    }
    }
    // Example usage after login
    async function loginAndGetProfile() {
    const loginResult = await loginWithFacebook();
    if (loginResult) {
    const profile = await getFacebookProfile();
    if (profile) {
    console.log('User ID:', profile.id);
    console.log('Name:', profile.name);
    console.log('Email:', profile.email);
    console.log('Profile Picture:', profile.picture?.data?.url);
    }
    }
    }

    令牌类型限制:该 getProfile 调用仅在您有令牌时才有效 访问令牌 (标准登录允许跟踪). 如果用户拒绝跟踪或您正在使用有限登录(仅限 JWT 令牌),则此调用将失败。 在这种情况下,请使用初始登录响应中提供的配置文件数据。

⚠️ Critical: 后端令牌处理

⚠️ Critical: 后端令牌处理

您的后端必须处理 两个不同的令牌类型 因为 iOS 用户可以根据 App Tracking Transparency 的选择接收 access 令牌或 JWT 令牌,而 Android 用户总是接收 access 令牌。

各平台令牌类型

Token Types by Platform
平台Token Types by PlatformToken Types by PlatformToken Types by Platform
Token Types by PlatformtrueToken Types by PlatformToken Types by Platform
Token Types by PlatformfalseToken Types by PlatformToken Types by Platform
Token Types by Platformfalse拒绝跟踪__CAPGO_KEEP_0__
Android任何N/A__CAPGO_KEEP_0__ (始终)

后端实现

后端实现
  1. 检测令牌类型并处理

    async function loginWithFacebook() {
    try {
    const loginResult = await SocialLogin.login({
    provider: 'facebook',
    options: {
    permissions: ['email', 'public_profile'],
    limitedLogin: false // iOS: depends on ATT, Android: ignored
    }
    });
    if (loginResult.accessToken) {
    // Access token (Android always, iOS when tracking allowed)
    return handleAccessToken(loginResult.accessToken.token);
    } else if (loginResult.idToken) {
    // JWT token (iOS only when tracking denied or limitedLogin: true)
    return handleJWTToken(loginResult.idToken);
    }
    } catch (error) {
    console.error('Facebook login error:', error);
    }
    }
  2. Firebase 集成示例

    import { OAuthProvider, FacebookAuthProvider, signInWithCredential } from 'firebase/auth';
    async function handleAccessToken(accessToken: string, nonce: string) {
    // For access tokens, use OAuthProvider (new method)
    const fbOAuth = new OAuthProvider("facebook.com");
    const credential = fbOAuth.credential({
    idToken: accessToken,
    rawNonce: nonce
    });
    try {
    const userResponse = await signInWithCredential(auth, credential);
    return userResponse;
    } catch (error) {
    console.error('Firebase OAuth error:', error);
    return false;
    }
    }
    async function handleJWTToken(jwtToken: string) {
    // For JWT tokens, send to your backend for validation
    try {
    const response = await fetch('/api/auth/facebook-jwt', {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json',
    },
    body: JSON.stringify({ jwtToken })
    });
    const result = await response.json();
    return result;
    } catch (error) {
    console.error('JWT validation error:', error);
    return false;
    }
    }
  3. 后端 JWT 验证

    // Backend: Validate JWT token from Facebook
    import jwt from 'jsonwebtoken';
    import { Request, Response } from 'express';
    app.post('/api/auth/facebook-jwt', async (req: Request, res: Response) => {
    const { jwtToken } = req.body;
    try {
    // Verify JWT token with Facebook's public key
    // See: https://developers.facebook.com/docs/facebook-login/limited-login/token/validating/#standard-claims
    const decoded = jwt.verify(jwtToken, getFacebookPublicKey(), {
    algorithms: ['RS256'],
    audience: process.env.FACEBOOK_APP_ID,
    issuer: 'https://www.facebook.com' // From: https://www.facebook.com/.well-known/openid-configuration/?_rdr
    });
    // Extract user info from JWT
    const userInfo = {
    id: decoded.sub,
    email: decoded.email,
    name: decoded.name,
    isJWTAuth: true
    };
    // Create your app's session/token
    const sessionToken = createUserSession(userInfo);
    res.json({
    success: true,
    token: sessionToken,
    user: userInfo
    });
    } catch (error) {
    console.error('JWT validation failed:', error);
    res.status(401).json({ success: false, error: 'Invalid token' });
    }
    });
  4. 通用后端令牌处理器

    // Handle both token types in your backend
    async function authenticateFacebookUser(tokenData: any) {
    if (tokenData.accessToken) {
    // Handle access token - validate with Facebook Graph API
    const response = await fetch(`https://graph.facebook.com/me?access_token=${tokenData.accessToken}&fields=id,name,email`);
    const userInfo = await response.json();
    return {
    user: userInfo,
    tokenType: 'access_token',
    expiresIn: tokenData.expiresIn || 3600
    };
    } else if (tokenData.jwtToken) {
    // Handle JWT token - decode and validate
    // See: https://developers.facebook.com/docs/facebook-login/limited-login/token/validating/#standard-claims
    const decoded = jwt.verify(tokenData.jwtToken, getFacebookPublicKey());
    return {
    user: {
    id: decoded.sub,
    name: decoded.name,
    email: decoded.email
    },
    tokenType: 'jwt',
    expiresIn: decoded.exp - Math.floor(Date.now() / 1000)
    };
    } else {
    throw new Error('No valid token provided');
    }
    }

重要考虑因素

重要考虑因素

访问令牌(标准登录):

  • Android: 总是可用(iOS-only 限制不适用)
  • iOS: 只有当用户明确允许应用跟踪时
  • ✅ 可用于访问 Facebook Graph API
  • ✅ 更长的过期时间
  • ✅ 可获得更多用户数据
  • iOS 设备上使用率逐渐下降 随着用户越来越多拒绝跟踪

JWT Token (iOS-Only Privacy Mode):

  • Android不支持
  • iOS当跟踪被拒绝或 limitedLogin: true
  • ✅ 遵守 iOS 用户隐私偏好
  • ❌ 只包含基本用户信息
  • ❌ 过期时间更短
  • ❌ 无法访问 Facebook Graph API
  • ⚠️ iOS 用户中最常见的场景

平台特定行为:

  • iOS应用: 必须处理两种类型的令牌:访问令牌和 JWT 令牌
  • Android应用: 只需处理访问令牌
  • 跨平台应用: 必须实现两种令牌处理方法

Web安全上下文要求(Web/API)”

Section titled “Crypto API Limitations”

Facebook登录流程更新需要 Web Crypto API 用于生成随机数的Web Crypto API,仅在 安全上下文中可用:

// This requires secure context (HTTPS or localhost)
async function sha256(message: string) {
const msgBuffer = new TextEncoder().encode(message);
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer); // ❌ Fails in insecure context
// ...
}

常见问题: ionic serve HTTP URL导致的Facebook认证问题

环境API 加密可用Facebook 登录可用
http://localhost:3000✅ 是✅ 是
http://127.0.0.1:3000✅ 是✅ 是
http://192.168.1.100:3000❌ 否❌ 否
https://any-domain.com✅ 是✅ 是

Capacitor 开发的解决方案

解决方案Capacitor开发
  1. 使用localhost进行web测试

    终端窗口
    # Instead of ionic serve --host=0.0.0.0
    ionic serve --host=localhost
  2. 在Ionic中启用HTTPS

    终端窗口
    ionic serve --ssl
  3. 在实际设备上测试

    终端窗口
    # Capacitor apps run in secure context on devices
    ionic cap run ios
    ionic cap run android
  4. 开发环境的替代nonce生成

    async function generateNonce() {
    if (typeof crypto !== 'undefined' && crypto.subtle) {
    // Secure context - use crypto.subtle
    return await sha256(Math.random().toString(36).substring(2, 10));
    } else {
    // Fallback for development (not secure for production)
    console.warn('Using fallback nonce - not secure for production');
    return btoa(Math.random().toString(36).substring(2, 10));
    }
    }

Firebase 集成注意事项

Firebase 集成注意事项

最近的 Firebase 文档要求使用 JWT 令牌和非法令牌(nonce)进行 Facebook 验证,無論登录设置如何。这种方法适用于两种情况 limitedLogin: truelimitedLogin: false:

// Both modes can return JWT tokens depending on user choice
const loginResult = await SocialLogin.login({
provider: 'facebook',
options: {
permissions: ['email', 'public_profile'],
limitedLogin: false, // true = always JWT, false = depends on user tracking choice
nonce: nonce
}
});

开发限制: 如果您在使用 ionic serve on a network IP (not localhost), Facebook login will fail due to crypto API restrictions. Use localhost or HTTPS for web testing.

故障排除

故障排除

常见问题和解决方案

常见问题和解决方案
  1. Android 上的密钥哈希错误

    • 请确认您已在 Facebook 控制台中添加了正确的密钥哈希
    • 对于发布版本,请确保已添加了 debug 和 release 密钥哈希
    • 生成哈希时,请确认您正在使用正确的 keystore
  2. Facebook 登录按钮未显示

    • 请确认所有清单条目都是正确的
    • 请确认您的 Facebook App ID 和 Client Token 是正确的
    • 请确认已正确初始化 SDK
  3. iOS 通用问题

    • 确保所有 Info.plist 条目都是正确的
    • 验证 URL 方案是否正确配置
    • 检查您的包 ID 是否与 Facebook 控制台中注册的 ID 匹配

测试

测试
  1. 在测试之前,在 Facebook 开发者控制台中添加测试用户

    • 去到角色 > 测试用户
    • 创建测试用户
    • 使用这些凭证进行测试
  2. 测试 debug 和 release 版本

    • debug 版本使用 debug key hash
    • 使用发布密钥哈希发布构建
    • 在模拟器和物理设备上测试

请记住测试完整的登录流程,包括:

  • 登录成功
  • 取消登录
  • 错误处理
  • 注销功能

继续Facebook登录设置

继续Facebook登录设置

如果您正在使用 Facebook登录设置 来规划身份验证和帐户流程,连接它 使用 @capgo/capacitor-social-login 为原生能力在 使用 @capgo/capacitor-social-login @capgo/capacitor-social-login 为实现细节在 @capgo/capacitor-social-login @capgo/capacitor-passkey 为实现细节在 @capgo/capacitor-passkey @capgo/capacitor-native-biometric 为实现细节在 @capgo/capacitor-native-biometric, 和 双因素认证 为实现细节在 双因素认证