今更感も否めませんが、CakePHP2.x系の話。3でも同じことが起きるのかもしれない。
問題の概要
既存のCakePHP2アプリ(Session管理にRedisを利用)にfacebook/php-sdk-v4(~5.0)を使ってソーシャルログイン機能を追加しようとしても
Cross-site request forgery validation failed. Required param "state" missing from persistent data.
という例外が発生して、上手くアクセストークンを取得できない。
なぜか
どうも、CakePHPのSessionとFacebookSDKのSessionが競合しているようで、SDKのDocument通りsession_start()とかしたら、今度はCakePHPのSessionが上手く機能しなくなり、setFlash等のメッセージが表示されないといったトラブルが起きる。
どうする
php-sdk-v4のセッション管理をCakePHPっぽく書いてあげれば問題を回避できる。
具体的には、FacebookSessionPersistentDataHandlerを修正する。
FacebookSessionPersistentDataHandler.php
/**
* @inheritdoc
*/
public function get($key)
{
if (isset($_SESSION[$this->sessionPrefix . $key])) {
return $_SESSION[$this->sessionPrefix . $key];
}
return null;
}
/**
* @inheritdoc
*/
public function set($key, $value)
{
$_SESSION[$this->sessionPrefix . $key] = $value;
}
ここを
FacebookSessionPersistentDataHandler.php
/**
* @inheritdoc
*/
public function get($key)
{
if(\CakeSession::read($this->sessionPrefix . $key)){
return \CakeSession::read($this->sessionPrefix . $key);
}
return null;
}
/**
* @inheritdoc
*/
public function set($key, $value)
{
\CakeSession::write($this->sessionPrefix.$key,$value);
}
このような形でCakeSessionに書き換える。
ただ、これだけでは上手く行かない場合があるので、その時はFacebookRedirectLoginHelper::getAccessToken, ::getLoginUrlなど、Sessionを使うメソッドの呼び出し前に
CakeSession::start();
#あるいは
\CakeSession::start()
で明示的にSessionをスタートさせてあげれば良かった。