Facebook Login 配置
复制包含安装步骤和该插件完整 Markdown 指南的配置 prompt。
在本指南中,你将学习如何使用 Capgo Social Login 配置 Facebook Login。你需要准备以下内容:
- Facebook Developer Account
- 应用的 package name/bundle ID
- 用于生成 key hashes 的终端访问权限 (Android)
如果你还没有创建过 Facebook App,请按以下步骤操作:
-
创建一个 Facebook App
按照教程 创建 App
-
将 Facebook Login 添加到你的 App
在 Facebook Developer Dashboard 中,将 Facebook Login 产品添加到你的 App
-
在向公众发布 App 之前,请先按照以下步骤 教程 完成发布
重要信息
标题为“重要信息”的章节集成所需的关键信息可以在以下位置找到:
-
CLIENT_TOKEN:
-
APP_ID:
-
APP_NAME:
Facebook 商务登录
“Facebook Business Login” 章节本插件支持 Facebook Business Login,用于处理业务相关的特性与权限。商务账号可以申请标准消费者登录之外的额外权限,包括 Instagram 和 Pages 的管理权限。
支持的业务权限包括:
instagram_basic- Instagram Basic Display API 的访问权限instagram_manage_insights- Instagram Insights 的访问权限pages_show_list- 该用户管理的 Pages 列表pages_read_engagement- 读取 Pages 的互动数据pages_manage_posts- 管理 Pages 上的帖子business_management- 管理业务资产
请参阅 Facebook 权限参考 查看完整权限列表。
配置要求:
- 你的 Facebook 应用必须在 Facebook Developer Console 中配置为 Business 应用。
- 在正式环境使用前,Business 权限可能需要通过 Facebook App Review。
- 你的应用必须遵守 Facebook 的 Business Use Case 政策。
Instagram 基础访问权限
标题为“Instagram 基础访问权限”的章节await SocialLogin.initialize({ facebook: { appId: 'your-business-app-id', clientToken: 'your-client-token', },});
const res = await SocialLogin.login({ provider: 'facebook', options: { permissions: [ 'email', 'public_profile', 'instagram_basic', 'pages_show_list', 'pages_read_engagement', ], },});
const profile = await SocialLogin.providerSpecificCall({ call: 'facebook#getProfile', options: { fields: ['id', 'name', 'email', 'instagram_business_account'], },});Pages 管理
“页面管理”章节const res = await SocialLogin.login({ provider: 'facebook', options: { permissions: [ 'email', 'pages_show_list', 'pages_manage_posts', 'pages_read_engagement', ], },});
const profile = await SocialLogin.providerSpecificCall({ call: 'facebook#getProfile', options: { fields: ['id', 'name', 'accounts{id,name,instagram_business_account}'], },});重要提示:
- 在提交 App Review 之前,您可以使用测试用户和开发版 App 来测试业务权限。
- 大多数业务权限在投入生产环境使用前,都需要通过 Facebook App Review。
- Business APIs 的速率限制(rate limits)各不相同。发布前请查阅 Facebook 最新的平台文档。
- 按照 Facebook 业务集成指南 配置 App 时。
Android 配置
“Android 设置”章节-
为您的项目添加网络权限
AndroidManifest.xml请确保包含以下代码行:
<uses-permission android:name="android.permission.INTERNET"/> -
生成 Android Key Hash
这是 Facebook 要求的关键安全步骤。请打开终端并运行:
终端窗口 keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64 -A当提示输入密码时,请输入:
android -
将 key hash 添加到你的 Facebook 应用
- 前往 Facebook Developers 中你应用的 dashboard
- 进入 Settings > Basic
- 向下滚动到 “Android” 部分
- 如果还没添加 Android,点击 “Add Platform” 并填写详细信息
- 添加你生成的 key hash
- 生产环境请同时添加 debug 和 release 的 key hash
-
更新您的
AndroidManifest.xml包含以下内容:<application>...<activity android:name="com.facebook.FacebookActivity"android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"android:label="@string/app_name" /><activityandroid: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>
iOS 配置
“iOS 设置”章节-
在 Facebook Developer Console 中添加 iOS 平台
- 前往 Facebook Developers 中你应用的 dashboard
- 进入 Settings > Basic
- 滚动到页面底部,点击 “Add Platform”
- 选择 iOS 并填写所需详情
-
打开 Xcode 项目并找到 Info.plist
-
在 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> -
修改
AppDelegate.swiftimport FBSDKCoreKit@UIApplicationMainclass AppDelegate: UIResponder, UIApplicationDelegate {func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {// Override point for customization after application launch.// Initialize Facebook SDKFBSDKCoreKit.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 callif (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 Login
标题为 “Using Facebook Login in Your App” 的章节-
在应用中初始化 Facebook 登录
import { SocialLogin } from '@capgo/capacitor-social-login';// Initialize during app startupawait SocialLogin.initialize({facebook: {appId: 'APP_ID',clientToken: 'CLIENT_TOKEN',}}) -
实现登录功能
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}} -
获取用户个人资料数据
登录成功后,您可以获取额外的个人资料信息:
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 loginasync 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);}}}Token 类型限制:
getProfile仅在您拥有以下内容时调用才有效: 访问令牌 (允许追踪的标准登录)。如果用户拒绝了追踪,或者您使用的是受限登录(仅 JWT token),则此调用会失败。在这种情况下,请使用初始登录响应中提供的 profile 数据。
⚠️ 关键:后端 Token 处理
“⚠️ 重要:后端 Token 处理”章节您的后端必须处理 两种不同的 token 类型 因为 iOS 用户根据其 App Tracking Transparency 的选择,可能会收到 access token 或 JWT token,而 Android 用户始终收到 access token。
各平台的 Token 类型
标题为“按平台划分的 Token 类型”的部分| 平台 | limitedLogin 设置 | 用户 ATT 选择 | 结果 Token 类型 |
|---|---|---|---|
| iOS | true | 任意 | JWT Token |
| iOS | false | 允许追踪 | 访问令牌 (Access Token) |
| iOS | false | 拒绝追踪 | JWT Token(自动覆盖) |
| Android | 任意 | 不适用 | Access Token(始终) |
后端实现
“后端实现”章节-
检测 Token 类型并进行相应处理
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);}} -
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 validationtry {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;}} -
后端 JWT 校验
// Backend: Validate JWT token from Facebookimport 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-claimsconst 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 JWTconst userInfo = {id: decoded.sub,email: decoded.email,name: decoded.name,isJWTAuth: true};// Create your app's session/tokenconst 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' });}}); -
通用后端 Token 处理器
// Handle both token types in your backendasync function authenticateFacebookUser(tokenData: any) {if (tokenData.accessToken) {// Handle access token - validate with Facebook Graph APIconst 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-claimsconst 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');}}
关键注意事项
标题为“关键注意事项”的章节Access Token (标准登录):
- ✅ Android: 始终可用 (不受 iOS 限制影响)
- ✅ iOS: 仅在用户明确允许应用追踪时可用
- ✅ 可用于访问 Facebook Graph API
- ✅ 有效期更长
- ✅ 可获取更多用户数据
- ❌ 在 iOS 上已逐渐减少使用 因为用户越来越多地拒绝追踪
JWT Token (仅限 iOS 的隐私模式):
- ❌ Android: 不会发生 (不支持)
- ✅ iOS: 当拒绝追踪时,或
limitedLogin: true - ✅ 符合 iOS 用户隐私偏好
- ❌ 仅包含基础用户信息
- ❌ 有效期较短
- ❌ 无法访问 Facebook Graph API
- ⚠️ 目前 iOS 用户最常见的场景
平台差异化行为:
- iOS 应用: 必须同时处理 access token 和 JWT token
- Android 应用: 仅需处理 access token
- 跨平台应用: 必须实现两种 token 处理方式
安全上下文要求 (Web/Capacitor)
章节标题为“安全上下文要求 (Web/Capacitor)”Crypto API 限制
“Crypto API 限制”章节更新后的 Facebook 登录流程需要使用 Web Crypto API 来生成 nonce,而这仅在 安全上下文 (secure contexts) 中可用:
// 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 身份验证失败
| 环境 | Crypto API 可用性 | Facebook 登录功能正常 |
|---|---|---|
http://localhost:3000 | ✅ 是 | ✅ 是 |
http://127.0.0.1:3000 | ✅ 是 | ✅ 是 |
http://192.168.1.100:3000 | ❌ 否 | ❌ 否 |
https://any-domain.com | ✅ 是 | ✅ 是 |
Capacitor 开发解决方案
标题为“Capacitor 开发解决方案”的部分-
使用 localhost 进行 Web 测试
终端窗口 # Instead of ionic serve --host=0.0.0.0ionic serve --host=localhost -
在 Ionic 中启用 HTTPS
终端窗口 ionic serve --ssl -
在真机上进行测试
终端窗口 # Capacitor apps run in secure context on devicesionic cap run iosionic cap run android -
开发环境下的备选 nonce 生成方式
async function generateNonce() {if (typeof crypto !== 'undefined' && crypto.subtle) {// Secure context - use crypto.subtlereturn 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 文档要求 Facebook 身份验证使用带 nonce 的 JWT token,无论登录设置如何。此方法同时适用于 limitedLogin: true 以及 limitedLogin: 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 网络 IP(而非 localhost)上使用,Facebook 登录会因 crypto API 限制而失败。Web 测试请使用 localhost 或 HTTPS。
故障排除
“故障排除”章节常见问题与解决方案
常见问题与解决方案-
Android 端 Key Hash 错误
- 请再次确认已将正确的 Key Hash 添加到 Facebook dashboard
- 对于 Release 版本,请确保同时添加了 debug 和 release 的 Key Hash
- 验证生成 Hash 时使用的是否为正确的 keystore
-
Facebook 登录按钮未显示
- 验证所有 manifest 配置是否正确
- 检查 Facebook App ID 和 Client Token 是否正确
- 确保已正确初始化 SDK
-
常见 iOS 问题
- 确保所有 Info.plist 配置项均正确
- 验证 URL schemes 配置是否正确
- 检查 Bundle ID 是否与 Facebook dashboard 中注册的一致
测试
“测试”章节-
测试前,请在 Facebook Developer Console 中添加测试用户
- 前往 Roles > Test Users
- 创建测试用户
- 使用这些凭据进行测试
-
测试 debug 和 release builds
- 使用 debug key hash 的 debug build
- 使用 release key hash 的 release build
- 在模拟器和真机上均进行测试
请务必测试完整的登录流程,包括:
- 成功登录
- 取消登录
- 错误处理
- 登出功能
从 Facebook Login 配置继续
标题为“继续完成 Facebook Login 设置”的部分如果你正在使用 Facebook Login 配置 用来规划身份验证和账户流程,并将它与 使用 @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 中的实现细节, 双因素认证 有关双重身份验证的实现细节。