前回のエントリで若干触れたのでペタリ。
<?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。
※本来はここもリスナーでやったほうがなおベター。