PHP
OAuth
laravel
FacebookSDK
FacebookGraphAPI

Laravel5 で Facebook graph-sdk を使うときに stateなんちゃらで怒られないようにする

More than 1 year has passed since last update.

Facebook API 使っていますか? 今までOAuthを毛嫌いしていてなかなか手を付けずにいたんですが、いざやってみたらチョーカンタン!なんですね。こりゃいいや。さっそくLaravelのプロジェクトにもサラッと組み込んで……。と思ったのに、まさか $_SESSION でコケてハマりました。

何がしたい?

Facebookログインの例 - facebook for developers
こちらがFacebook公式のサンプル。ほとんどこのまま動きますが、Laravelのプロジェクト内でサンプル通りやると

Cross-site request forgery validation failed. Required param "state" missing from persistent data.

と出てしまいます。"Cross-site"と聞いて一瞬クロスサイトスクリプティング的なややこしい問題が頭をよぎりましたが、要するに、「$_SESSIONに必要なセッション情報が保存されてない」ということです。

結論

CakePHPでFacebook php-sdk-v4使ってもstateなんちゃらで怒られないようにする
こちらを参考にさせていただきました(というかそのままです、すみません……)

ソースコードの中から、その$_SESSIONに保存しているところを探して、Laravelのやり方に変更します。
それが、FacebookSessionPersistentDataHandler.php で、Laravel風にするとこんな感じです。

FacebookSessionPersistentDataHandler.php
  public function __construct( $enableSessionCheck = true )
  {
  }

  public function get($key)
  {
      return \Illuminate\Support\Facades\Session::get($this->sessionPrefix . $key);
  }

  public function set($key, $value)
  {
      \Illuminate\Support\Facades\Session::put( $this->sessionPrefix . $key, $value );
  }

コンストラクタでは、もともとエラーチェックをしていてそのままだと「セッションが活きてないよ!」と怒られますので、まるごと削除しました。

結論2 - SDKのソースコードを書換えない方法

しかし上記コード。Facebook SDKの中のコードを書き換えるのは控えたいところ。SDKがバージョンアップした時に上書きされてしまうかもしれませんし、Facebook SDKの中にLaravelのコードが紛れ込んでしまうので再利用性が落ちます。
これを解決するには、Facebookオブジェクトに、上記の$_SESSIONに関する操作をする部分 = PersistentDataHandler を作って渡してあげればOKです。依存性注入(DI)ですね。
具体的にはFacebookオブジェクトを作るところが、下記のようになります。

SampleApp.php
class LaravelDataHandler extends \Facebook\PersistentData\FacebookSessionPersistentDataHandler {
  public function __construct( $enableSessionCheck = true )
  {  
  }

  public function get($key)
  {
      return Session::get($this->sessionPrefix . $key);
  }

  public function set($key, $value)
  {
      Session::put( $this->sessionPrefix . $key, $value );
      // var_dump(Session::all()); // デバッグ用:保存されたセッション情報をダンプ
  }
}

/* ... */

$facebook = new Facebook([
  'app_id' => 'xxxxxxxxxxxxx',
  'app_secret' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  'default_graph_version' => 'v2.10',
  'persistent_data_handler' => new LaravelDataHandler, // このオプションを追加
]);    

感想

最近ちょっとだけDIというものがナニかわかってきたので、言ってみたかっただけです(๑•̀ㅂ•́)و✧