前回のエントリで若干触れたのでペタリ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | <?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で下記のように定義してやり
※前回のエントリそのまんま。
1 2 3 4 5 6 7 | services: xsrf.token.manager: class: Hoge\FugaBundle\Services\XsrfTokenManager arguments: [@request, @form.csrf_provider] scope: request tags: - { name: xsrf.token.manager } |
レスポンスリスナあたりでset()メソッドを実行してやればOK。
1 2 3 4 5 6 7 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?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。
※本来はここもリスナーでやったほうがなおベター。