環境
- php7.0
- symfony2.8
やりたいこと
slackのoutgoing webhookから送られてくるリクエストのトークンが
正しいかどうかをコントローラでリクエストを受ける前に行いたい。
↓イメージ
/**
* リクエストの正当性を事前に確かめておきたい
*
* @param Request $request
*/
public function HogeAction(Request $request)
{
/**
* 正しいリクエストをサービスに投げて
* あとはよしなにやるようにする
*/
$this->get('service')->execute($request);
}
どうやるのか
公式によるとやりたいことはこれなのかなと
How to Set Up Before and After Filters
http://symfony.com/doc/2.8/event_dispatcher/before_after_filters.html
beforeフィルターを実装するつもりでやってみる。
手順
①バリデーションに使うtokenを設定
②チェックしたいコントローラにtokenチェックを行うかどうかを判別させるinterfaceを持たせる
↑は他のいい方法ありそう
③イベントリスナー作成
④作成したイベントリスナーの定義をymlファイルに書き込む
実践
バリデーションに使うtokenを設定
githubの公開リポジトリ使ってるのでconfig.ymlには書きません
parameters:
database_host: mysql
.
.
.
out_going_webhook_tokens:
client1: xxxx
client2: xxxx
チェックしたいコントローラにtokenチェックを行うかどうかを判別させるinterfaceを持たせる
interface作成
<?php
namespace AppBundle\Controller\Support;
interface SlackWebhookTokenAuthenticated
{
//空でok.
}
Controllerに↑を持たせる
<?php
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use AppBundle\Controller\Support\SlackWebhookTokenAuthenticated;
class HogeController implements SlackWebhookTokenAuthenticated
{
/**
* @param Request $request
*/
public function HogeAction(Request $request)
{
//$this->get('service')->execute($request);
}
}
イベントリスナー作成
<?php
namespace AppBundle\EventListener;
use AppBundle\Controller\Support\SlackWebhookTokenAuthenticated;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class SlackWebhookTokenListener
{
/**
* @var array
*/
private $outGoingWebhookTokens;
/**
* SlackWebhookTokenListener constructor.
*
* @param array $outGoingWebhookTokens
*/
public function __construct(array $outGoingWebhookTokens)
{
$this->outGoingWebhookTokens = $outGoingWebhookTokens;
}
/**
* @param FilterControllerEvent $event
*/
public function onKernelController(FilterControllerEvent $event)
{
$controller = $event->getController();
if (!is_array($controller)) {
return;
}
if ($controller[0] instanceof SlackWebhookTokenAuthenticated) {
$token = $event->getRequest()->query->get('token');
if (!in_array($token, $this->outGoingWebhookTokens)) {
throw new AccessDeniedHttpException('This action needs a valid token!');
}
}
}
}
作成したイベントリスナーの定義をymlファイルに書き込む
services:
app.slack_outgoing_webhook.action_listener:
class: AppBundle\EventListener\SlackWebhookTokenListener
arguments: ['%out_going_webhook_tokens%']
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
完成!!
あとはブラウザなりhttpクライアントツールでお試しください。。
まとめ
コントローラに空のインターフェースを実装させてタグみたいに使うのは
初めてだったので新鮮だった。
今回の方法だとコントローラごとイベントリスナーの対象となってしまうので
メソッドごとにできたらいいなと。
laravelだとそこらへんが簡単にできるんだけどなぁ。。
routingに対してmiddlewareとかショートカット名とか
直観的に簡単に設定できるのが○
symfonyは開発者が知らなければいけない設定項目がファイルごとに違うので
割と手間だなぁ。。
そこんとこ、laravelはプログラミングコードベースで管理できるのでわかりやすい。
ただ、symfonyはlaravelよりも自由が利かないようになっているので
固く書きたいならいいなと。
あと、phpstormの補完が便利すぎて震える。