前回のエントリで若干触れたのでペタリ。
<?php
namespace Hoge\FugaBundle\Services;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\SessionCsrfProvider;
class XsrfTokenManager
{
private $request;
private $provider;
protected $_cookieName = 'XSRF-TOKEN';
protected $_sessionName = 'S-XSRF-TOKEN';
const RECEIVED_HEADER_NAME = 'X-XSRF-TOKEN';
/**
* Construct
*/
public function __construct(Request $request, SessionCsrfProvider $provider)
{
$this->request = $request;
$this->provider = $provider;
}
/**
* check xsrf token matches
*
* @return boolean
*/
public function check()
{
$_header = $this->request->headers->get(self::RECEIVED_HEADER_NAME);
if (empty($_header) || $_header != $this->create()) {
throw new \Symfony\Component\Security\Core\Exception\AccessDeniedException();
}
return true;
}
/**
* generate strings of xsrf token
*
* @param string $salt
* @return \Hoge\FugaBundle\Services\XsrfTokenManager
*/
private function create($salt = 'csrf_token')
{
$request = $this->request;
$token = null;
if ($request->getSession() && $request->getSession()->has($this->_sessionName)) {
$token = $request->getSession()->get($this->_sessionName);
} else {
$token = $this->provider->generateCsrfToken($salt);
if ($request->getSession()) {
$request->getSession()->set($this->_sessionName, $token);
}
}
return $token;
}
/**
* set cookie for client
*
* @return boolean|\Symfony\Component\HttpFoundation\Cookie
*/
public function set()
{
$cookie = new Cookie($this->_cookieName, $this->create(), 0, '/', null, false, false);
$response = new Response();
$response->headers->setCookie($cookie);
$response->send();
return $cookie;
}
/**
* setter for cookie name
*
* @param unknown $name
* @return \Hoge\FugaBundle\Services\XsrfTokenManager
*/
public function setCookieName($name)
{
$this->_cookieName = $name;
return $this;
}
/**
* getter for cookie name
*
* @return string
*/
public function getCookieName()
{
return $this->_cookieName;
}
/**
* setter for session name
*
* @param unknown $name
* @return \Hoge\FugaBundle\Services\XsrfTokenManager
*/
public function setSessionName($name)
{
$this->_sessionName = $name;
return $this;
}
/**
* getter for session name
*
* @return string
*/
public function getSessionName()
{
return $this->_sessionName;
}
}
これをService.ymlで下記のように定義してやり
※前回のエントリそのまんま。
services:
xsrf.token.manager:
class: Hoge\FugaBundle\Services\XsrfTokenManager
arguments: [@request, @form.csrf_provider]
scope: request
tags:
- { name: xsrf.token.manager }
レスポンスリスナあたりでset()メソッドを実行してやればOK。
services:
listener.before.filter:
class: Hoge\FugaBundle\EventListener\ResponseListener
arguments: [@xsrf.token.manager]
scope: request
tags:
- { name: kernel.event_listener, event: kernel.response, method: createToken }
ResponseListenerは下記の通り。
\Hoge\FugaBundle\EventListener\ResponseListener.php
<?php
namespace Hoge\FugaBundle\EventListener;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Hoge\FugaBundle\Services\XsrfTokenManager;
class ResponseListener
{
protected $manager;
/**
* Construct
*/
public function __construct(XsrfTokenManager $manager)
{
$this->manager = $manager;
}
/**
* before filter event
*/
public function createToken()
{
$this->manager->set();
}
}
あとはトークンチェックが必要なコントローラーのアクション先頭でcheck()メソッドを呼んでやればOK。
※本来はここもリスナーでやったほうがなおベター。