集成Facebook快捷登录

4,677 阅读6分钟

一、概述

有时候,为了迅速获客,会在注册登录页支持第三方登录,目的是借用这些产品庞大的用户量。在国内,常见的第三方登录有微信、qq和微博。

image.png

对于一些国际的软件/网站来说,支持的比较多的第三方登录是Google、Facebook和Twitter等。这里记录下Facebook第三方登录的过程,下面是一个Facebook第三方登录流程说明。

image.png

流程说明如下:

  1. 用户点击Facebook登录按钮,客户端向Facebook发起请求,用户在Facebook的页面输入登录信息,登录成功后Facebook回调客户端并带回用户的Facebook信息;
  2. 客户端把用户登录Facebook的token发送至服务端,服务端调Facebook的token验证接口验证token是否有效;
  3. 如果有效,则Facebook第三方登录成功,否则登录失败。

 

二、创建Facebook应用

 

2.1 Facebook应用配置

首先,打开Facebook官网(现在叫Meta)developers.facebook.com/

image.png  

如果还没有开发者账号,可以点击右上角的【立即开始】按钮创建一个开发者账号。

image.png

创建完成之后,点击创建应用创建一个应用,如下图。

image.png

image.png

image.png

当然,我们也可以为应用添加一些产品, 可以添加Android、IOS、web页面等类型的授权登录。

image.png  

2.2 前端授权

首先,需要配置回调地址。这里以网页版的授权为例,如果开发网页版的Facebook授权登录,需要在Facebook后台配置有效OAuth跳转URI,就是用户在Facebook登录页面登录成功之后需要回调到部署你自己的登录页面的服务器地址。

image.png

关于授权登录sdk,Facebook官方提供了详细的说明,也有现成的sdk和完整的demo。官方文档: developers.facebook.com/docs/facebo…

下面是前端示例:login.html

<html>
    <head>
        <script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v6.0&appId=746492673568696&autoLogAppEvents=1"></script>
        <script>
            function login() {
                FB.login(function(response){
                    console.log(response);
                });
            }
        </script>
    </head>
    <body>
        <h1>Facebook登录</h1>
        <!-- 自定义登录按钮 -->
        <button id="loginBtn" onclick="login();" >登录</button> 
    </body>
</html>

这个网页不能直接用浏览器打开,需要部署在支持Https的服务器上。

image.png

登录成功之后,就可以看到控制台打印出了登录成功后Facebook返回的信息,有accessToken、userID等内容。

image.png

2.3 后端校验

 前端拿到Facebook的登录token后,接下来就是我们自己后端的校验逻辑,为了防止别人拿其他平台的appId授权的token来请求,后端可以可以使用下面的方式来校验token。

https://graph.facebook.com/debug_token?access_token={App-token}&input_token={User-token}

上面这个接口就是用来校验token的。User-token为用户登录的token(比如上面用户登录返回的accessToken),App-token是由appId和appSecret拼接而成。校验后,返回的数据格式如下:

{
    "data": {
        "app_id": "746492673568696",
        "type": "USER",
        "application": "shop",
        "data_access_expires_at": 1594896505,
        "expires_at": 1587124800,
        "is_valid": true,
        "scopes": [
            "user_birthday",
            "user_likes",
            "user_photos",
            "user_friends",
            "user_status",
            "email",
            "public_profile"
        ],
        "user_id": "110029804771531"
    }
}

 其中is_valid就是token是否校验成功。如果还需要获取其他用户信息,可以参考Facebook提供的api:developers.facebook.com/docs/graph-…

三、Flutter集成

3.1 Flutter集成

首先,在项目中flutter_facebook_auth插件依赖,如下所示。

dependencies:
  flutter_facebook_auth: ^4.4.0

完成上述依赖后,接下来只需要在应用启动的地方使用下面的代码初始化即可。

import 'dart:convert';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'my_app.dart';


void main() async {
  if (kIsWeb) {
    // initialiaze the facebook javascript SDK
    await FacebookAuth.instance.webInitialize(
      appId: "1329834907365798",
      cookie: true,
      xfbml: true,
      version: "v14.0",
    );
  }
  runApp(MyApp());
}


String prettyPrint(Map json) {
  JsonEncoder encoder = new JsonEncoder.withIndent('  ');
  String pretty = encoder.convert(json);
  return pretty;
}

 

四、原生集成

4.1 原生Android接入

然后,打开Facebook的开发者后台获取Facebook快捷登录所需的帐号等信息。同时,为确保您的应用和 Facebook 之间互动的真实性,您需要向我们提供适用于您开发环境的 Android 密钥散列。

其中,Mac OS生成开发密钥散列的命令如下:

keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

image.png  

接着点击【下一步】,然后打开/app/res/values/strings.xml 文件,并添加名称为 facebook_app_id、fb_login_protocol_scheme 以及 facebook_client_token 的 string 元素。

<string name="facebook_app_id">1234</string>
<string name="fb_login_protocol_scheme">fb1234</string>
<string name="facebook_client_token">56789</string>

然后,打开 /app/manifest/AndroidManifest.xml 文件,将meta-data元素添加到应用编号和客户端口令的 application 元素中。

<application android:label="@string/app_name" ...>
    ...
   	<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
   	<meta-data android:name="com.facebook.sdk.ClientToken" android:value="@string/facebook_client_token"/>
    ...
</application>

然后,在 application 元素中为 Facebook 注册相应的页面,并为 Chrome 自定义选项卡添加活动和意图筛选条件。

<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="@string/fb_login_protocol_scheme" />
        </intent-filter>
    </activity>

在 Android 系统内,SDK 的应用启用辅助方法应在应用创建后立即调用,因此需要在Application 类的 onCreate()方法中放置如下代码:

@Override
public void onCreate() {
    super.onCreate();
    FacebookSdk.sdkInitialize(getApplicationContext());
    AppEventsLogger.activateApp(this);
}

其中,AppEventsLogger用于记录事件的。为了方便监听回调的结果,Facebook提供了一个 CallbackManager.Factory.create 方法。

callbackManager = CallbackManager.Factory.create();

 

下面是一段获取登录情况的回调代码。

 private static final String EMAIL = "email";
      
    loginButton = (LoginButton) findViewById(R.id.login_button);
    loginButton.setReadPermissions(Arrays.asList(EMAIL));
  
    loginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
        @Override
        public void onSuccess(LoginResult loginResult) {
            // App code
        }


        @Override
        public void onCancel() {
            // App code
        }


        @Override
        public void onError(FacebookException exception) {
            // App code
        }
    });

如果需要响应登录结果,需要使用 LoginManager 或 LoginButton 注册回调。如果使用 LoginButton 注册回调,则无需再使用 LoginManager 注册回调。

    callbackManager = CallbackManager.Factory.create();      
      
    LoginManager.getInstance().registerCallback(callbackManager,
            new FacebookCallback<LoginResult>() {
                @Override
                public void onSuccess(LoginResult loginResult) {
                    // App code
                }


                @Override
                public void onCancel() {
                     // App code
                }


                @Override
                public void onError(FacebookException exception) {
                     // App code   
                }
    });

如果登录成功,LoginResult 参数会获得新的 AccessToken,以及最新授予或拒绝的权限。最后,还可以使用 onActivityResult 方法调用 callbackManager.onActivityResult,从而通过 callbackManager 将登录结果传递到 LoginManager。

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        callbackManager.onActivityResult(requestCode, resultCode, data);
        super.onActivityResult(requestCode, resultCode, data);
    }

 

4.2 原生iOS接入

首选,将项目需要支持Swift以及platform 设置成11.0+,然后将Bundle Identifier关联到Facebook创建的项目。

image.png

然后,使用打开Info.plist 文件。右键点击【 Info.plist】,然后选择 【Open As】->【Source Code】源代码的方式打开。接着,将下列 XML 代码片段复制并粘贴到文件正文中 (...)。

<key>CFBundleURLTypes</key>
<array>
  <dict>
  <key>CFBundleURLSchemes</key>
  <array>
    <string>fbAPP-ID</string>
  </array>
  </dict>
</array>
<key>FacebookAppID</key>
<string>APP-ID</string>
<key>FacebookClientToken</key>
<string>CLIENT-TOKEN</string>
<key>FacebookDisplayName</key>
<string>APP-NAME</string>
  • 在 [CFBundleURLSchemes] 键内的 中,将 APP-ID 替换为您的应用编号。
  • 在 FacebookAppID 键内的 中,将 APP-ID 替换为您的应用编号。
  • 在 FacebookClientToken 键内的 中,将 CLIENT-TOKEN 替换为您在应用面板设置 > 高级 > 客户端口令中找到的值。
  • 在 FacebookDisplayName 键内的 中,将 APP-NAME 替换为您的应用名称。

 

如果需要将应用切换至 Facebook 应用的 Facebook 对话框(如登录、分享、应用邀请等),应用程序的 Info.plist 还需包含以下代码:

<key>LSApplicationQueriesSchemes</key>
<array>
  <string>fbapi</string>
  <string>fb-messenger-share-api</string>
</array>

 

为了能够让Facebook顺利完成登录,需要在应用启动时初始化SDK,所以需要将 AppDelegate.swift 方法中的代码替换为以下代码。

// AppDelegate.swift
import UIKit
import FacebookCore


@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {    
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {          
        ApplicationDelegate.shared.application(
            application,
            didFinishLaunchingWithOptions: launchOptions
        )


        return true
    }
          
    func application(
        _ app: UIApplication,
        open url: URL,
        options: [UIApplication.OpenURLOptionsKey : Any] = [:]
    ) -> Bool {
        ApplicationDelegate.shared.application(
            app,
            open: url,
            sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
            annotation: options[UIApplication.OpenURLOptionsKey.annotation]
        )
    }  
}

iOS 13 版本的系统中,将打开网址的功能移到了SceneDelegate 中。如果您使用的是 iOS 13 版本,请将以下方法添加到 SceneDelegate 中。

// SceneDelegate.swift
import FacebookCore
  ...
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    guard let url = URLContexts.first?.url else {
        return
    }


    ApplicationDelegate.shared.application(
        UIApplication.shared,
        open: url,
        sourceApplication: nil,
        annotation: [UIApplication.OpenURLOptionsKey.annotation]
    )
}

接下来,我们就可以使用AccessToken来获取用户登录状态了。

override func viewDidLoad() {
    super.viewDidLoad()


    if let token = AccessToken.current,
        !token.isExpired {
        // User is logged in, do work such as go to next view controller.
    }
}
    

获取登录的token以及用户id后,接下来就是根据后端需求进行账号绑定操作了。