1.前置き
laravelは便利ですね。facebookを利用したソーシャルログインなども簡単に導入できます。
通知(notification)にfacebookを使うのも、Laravel Notification Channelsでfacebookが用意されているから、簡単にできるだろうとたかをくくっていました。
確かにこれを利用すればlaravel側の設定はさほど難しくないのですが、上記リンク先で$this->user->fb_messenger_idとされている部分をどうすればよいかに悩みました。
上記リンク先でも説明されているように、各ユーザーのfacebookのPSIDが必要になります。
そのfacebookのPSIDを入手し、さらにPSIDを自サイトで管理しているユーザーと紐付けるのに相当苦労しました。
わかりやすく解説しているページもざっと見た限りなかったので、ここにまとめます。
2.facebookにおけるIDの概念
具体的な手順に入る前に、facebookにおけるIDの概念を理解するのが近道です。
開発者にとって重要なのは、ASID(Application Scoped ID)とPSID(Page Scoped ID)です。
これらは、開発者が作成するアプリのIDやページのIDとは違い、ユーザーごとに異なる値です。
ただし、facebookにログインして自分の名前をクリックした際にURL欄に表示されるユーザーIDとも異なり、アプリやページごとに限定されたIDです。
ASIDはユーザーがfacebookログインをした際に開発者サイドで取得することができます。
PSIDはユーザーがfacebookのmessengerを利用した際にeventとしてwebhookに送信されます。
以上より、laravelのnotificationでfacebookを使うためには、次の手順を考えることになります。
(1) ユーザーがfacebookログインをした際にASIDをusersテーブルに保存する。
(2) ユーザーにmessengerを利用してもらい、eventとしてwebhookに送信されるPSIDを取得する。
(3) (2)で取得したPSIDと(1)で保存したASIDを紐付けする。
このIDの概念と流れを理解できたら具体的な手順に入りましょう。
3.手順
(1) ASIDの保存
Socialiteを用いたfacebookログインは実装できているという前提で、ここでは詳しく説明しません。
callbackでSocialite::driver(‘facebook’)->user()->getId()でASIDを取得できます。
これをusersテーブルの適当なカラム(fb_app_user_idなど)に保存してください。
migrationを使ってカラムを作成する方法は割愛します。
(2) PSIDの取得
まず、Facebook Messenger appを作成し、PAGE_ACCESS_TOKENを生成します。
次に、webhookのコールバックURLを設定します。localhostでテストするためにはngrokでトンネルを掘る必要があります。
Webhookの設定 – MessengerプラットフォームではNode.jsで説明されていますが、laravelならrouteとcontrollerを使ってgetとpostの設定をすればよいです。
getで行うWebhook認証のほうは、requestのqueryで送られてくるhub_challengeをreturnすればよいだけです。つまり、getのcontrollerは「return $request->input(‘hub_challenge’);」の一行だけでOKです。「hub.challenge」ではなく「hub_challenge」だということに気づかずハマりました。
次に、先ほど設定したWebhookを編集して、Message Delivered eventsをsubscribeするためにmessage_deliveriesにチェックを入れます。何らかの事情で初回アクセス時のイベントでPSIDを取得できなかったときのために、messagesにもチェックを入れておいたほうがよいです。
こうすることで、ユーザーがhttp://m.me/<PAGE_NAME>をクリックしたときに発生するMessage Delivered eventsから、そのユーザーのPSIDを取得することができます。具体的には、$request->input(‘entry.0.messaging.0.sender.id’)です。
これはpostで受け取りますので、VerifyCsrfTokenMiddlewareの除外設定を忘れないようにしてください。
(3) PSIDとASIDの紐付け
そのものズバリ、IDマッチングAPI – Messengerプラットフォームというページがあります。ID Matching API – Messengerプラットフォームもほぼ同じ内容です。
これらに沿って進めます。
ビジネスマネージャの概要からfacebookのビジネスを作成します。
仕事用メールアドレスの認証を経てビジネスを作成することができます。
そのビジネスに、facebookログインを実装する際に作成したアプリと、messengerのために先ほど作成したページの両方を登録します。
PSIDからASIDを取得したいので、以下のAPI呼び出しになります。
https:/
<ID>は先ほど取得したPSIDです。
同じビジネス内で複数のアプリを開発しているなら、<OPTIONAL_APP_ID>にアプリIDを入れます。
<ACCESS_TOKEN>は(2)の最初で作ったPAGE_ACCESS_TOKENです。
<APP_SECRET_PROOF>は、グラフAPIリクエストの保護で説明されているように、phpならhash_hmac(‘sha256’, \$access_token, \$app_secret)で生成します。
\$access_tokenはPAGE_ACCESS_TOKENです。\$app_secretは、facebookログインを実装する際に必要となるsecretの値です。
API呼び出しから返される結果から、そのPSIDユーザーのASIDを引っ張ってくることができます。
これをusersテーブルのfb_messenger_idカラムに格納すれば完成です。
あとは自由にそのユーザーに対してPSIDを使ってfacebookのmessageを送ることができます。
laravelのコードをまとめると次のようになります。
web.php
(略)
Route::get('/facebook/webhook', 'MessagingWebhookController@confirmFacebookMessaging');
Route::post('/facebook/webhook', 'MessagingWebhookController@receiveFacebookMessagingEvent');
(略)
VerifyCsrfToken.php
(略)
protected $except = [
'facebook/*',
];
(略)
MessagingWebhookController.php
(略)
use GuzzleHttp\Client;
use App\User;
(略)
//facebookのwebhook認証
public function confirmFacebookMessaging(Request $request) {
return $request->input('hub_challenge');
}
//facebookのイベントwebhook
public function receiveFacebookMessagingEvent(Request $request) {
$psid = $request->input('entry.0.messaging.0.sender.id');
$access_token = config('services.facebook.page-token');
$app_id = config('services.facebook.client_id');
$app_secret = config('services.facebook.client_secret');
$appsecret_proof = hash_hmac('sha256', $access_token, $app_secret);
$url = "https://graph.facebook.com/v2.6/$psid/ids_for_apps?app=$app_id&access_token=$access_token&appsecret_proof=$appsecret_proof";
$client = new Client();
$json = $client->request("GET", $url)->getBody();
$data = json_decode($json, true);
$asid = $data['data'][0]['id'];
User::where('fb_app_user_id', $asid)->update(['fb_messenger_user_id' => $psid]);
}
(略)
便宜上、Controllerにざっとコードを書いています。
エラーチェックやすでにPSIDとASIDの紐付けがされている場合の処理などは省略しています。
4.感想
FacebookのMessengerプラットフォームのドキュメントを熟読するしかないのですが、英語で表示されたり日本語で表示されたり、微妙に内容が違っていたりで混乱しました。
アカウントのリンク – Messengerプラットフォームを使ったほうがよいのかと思って実験してみたりもしましたが、ボタンがよくわからず、結局上で説明したやり方に落ち着きました。
これでやりたいことは実現できたのでよしとします。