App 整合 google-Facebook-paypal 社會化登入伺服器端開發指南

nosun 發表於 2020-06-30

一、寫在前面

以前做過好幾個站點涉及到社會化登入,主要使用的是 google,facebook。專案均採用 laravel 開發,使用官方外掛 "laravel/socialite" 就 ok 了,如果遇到 socialite 中沒有的 provider,則需前往 provider manager 倉庫安裝具體的 provider 了。

作為 web 專案,三方登入的 package 是比較成熟的,一般來說在網頁上建立一個三方登入的按鈕,跳轉到第三方平臺上登入,成功之後會跳轉到專案站點預設的 callback 路徑,在 callback 方法中做使用者在三方平臺登入之後在本站的認證操作。

近期,電商站點做 app,需要適配 app,一共要接入三個站點:facebook,google 和 paypal,本來以為 social 包就能處理,結果發現差異較大,浪費了不少的功夫,因此這裡做點小結。

二、Facebook 登入

facebook 是最容易對接的,也是直接能用 socialite 包拿到使用者資料的,app 那邊登入之後,可以拿到 access_token,並傳輸到後端,後端拿到 access_token 後直接可以拿到使用者的基本資料:

$userInfo = Socialite::driver($provider)->userFromToken($code);
$id = $userInfo->getId();
$name = $userInfo->getName();
$email = $userInfo->getEmail() ? $userInfo->getEmail() : $id;

三、google 登入

socialite 完全不能用,網上的文章也不靠譜。參考 google 官方文件 下載 google sdk 解決。

在所有工作開展之前,需要到 google 平臺上增加專案,並對專案進行設定,此處略去不表。

使用者在 google 登入之後,獲得了名叫 id_token 的東西,客戶端將 id_token 傳送到後臺伺服器,伺服器使用 id_token 獲取使用者資訊。

這個 id_token,是和 access_token 是類似的東西,有效期內可以使用多次,還可以通過瀏覽器進行測試:

https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123

在多次嘗試 socialite 庫解析使用者資料無效之後,通過瀏覽器測試確認了 token 所攜帶的資料內容,也確認了 socilalite 程式碼所提供的方法不能解析出使用者,不知道為何同樣是 oauth2,為何 google 對於 android 和 web 提供的方法不一致。

此處需要使用到 google 的 PHP sdk:composer require google/apiclient:"^2.0"

$client_id = config('service.google.client_id');

$client = new Google_Client(['client_id' => $client_id]);

try {
    $payload = $client->verifyIdToken($code);

    if ($payload) {
        return $payload;
  } else {
      throw new UnauthorizedHttpException("the token is invalid", 40110);
  }
} catch (\Throwable $exception) {
    throw new UnauthorizedHttpException("error when verify token from google", 40111);
}

四、paypal 登入

socialite 完全不能用,網上的文章也不靠譜。經過反覆折騰,看了paypal 無數的 API 文件,SDK 使用說明,沒有找到對路的辦法,最終參考 paypal connect 官方文件解決,就是一個字,累。

在沒有找到 Paypal connect 文件之前,在 paypal 的各種 api 文件中都檢索不出頭緒來。每次還需要客戶端給生成一個 token,想著拿到的應該類似 facebook 或者 google 的 access_token,用 socialite 庫直接讀出來就好,萬萬沒想到,這貨卻是一個 auth_code,需要在 server 端到 paypal server 上換一個 access_token,然後才能拿到使用者資訊。

先是按照官方文件的例子,用 postman 測試了下,確認了 api,最終使用了 PayPal-PHP-SDK,不過這貨也是一個坑,官方已經設定為 readonly 了,基本上已經棄用,方法中的 api 介面都是舊的,不過請求的格式沒太大變化,因此可以繼承一下官方類來換取 access_token 和解析使用者資料,等有空了,可以自己實現並維護一個庫。

獲取 access_token:

public static function getAccessToken($params, $apiContext)
    {
        static $allowedParams = array('grant_type' => 1, 'code' => 1);

        if (!array_key_exists('grant_type', $params)) {
            $params['grant_type'] = 'authorization_code';
        }

        $clientId = $apiContext->getCredential()->getClientId();
        $clientSecret = $apiContext->getCredential()->getClientSecret();

        $json = self::executeCall(
            "/v1/oauth2/token",
            "POST",
            http_build_query(array_intersect_key($params, $allowedParams)),
            array(
                'Content-Type' => 'application/x-www-form-urlencoded',
                'Authorization' => 'Basic ' . base64_encode($clientId . ":" . $clientSecret)
            ),
            $apiContext
        );

        $data = json_decode($json);

        return $data->access_token;
    }

獲取使用者資訊:

public static function getUserInfo($params, $apiContext = null)
{
    static $allowedParams = array('schema' => 1);

    $params = is_array($params) ? $params : array();

    if (!array_key_exists('schema', $params)) {
        $params['schema'] = 'paypalv1.1';
    }

    $requestUrl = "/v1/identity/oauth2/userinfo?"
        . http_build_query(array_intersect_key($params, $allowedParams));

    $json = self::executeCall(
        $requestUrl,
        "GET",
        "",
        array(
            'Authorization' => "Bearer " . $params['access_token'],
            'Content-Type' => 'x-www-form-urlencoded'
        ),
        $apiContext
    );

    $ret = new UserInfo();

    $ret->fromJson($json);

    return $ret;
}

順便,參考官方文件,寫了個簡單的頁面,並在頁面上放置一個跳轉按鈕,自己獲取 auth_code, 這樣再也不用依賴客戶端的同事給生 code 了,大大簡化了開發和測試流程。

五、結尾

小小的功能,寫了兩天,我也是醉了,究其原因有如下三點:

第一,是思想中過於依賴 socialite 庫,以為這貨考慮了 android 這樣的客戶端請求的情形,結果浪費了不少測試的事件。

第二,不得不吐槽 paypal 的官方文件了,可能因為 paypal 主要是做支付的,在 developer.paypal.com 中檢索內容,很難檢索到相關內容,最終還是產品的同事給了個連結💔。

第三,是測試方法的簡陋,每次登入都需要依賴客戶端給 code,導致沒辦法快速的定位問題,不知道是 token 的問題還是程式碼的問題。

來源:www.guohuawei.com/archives/how-to-s...

本作品採用《CC 協議》,轉載必須註明作者和本文連結