LoginSignup
3
3

More than 5 years have passed since last update.

[symfony2.8] httpリクエストをコントローラで受ける前にmiddleware的なやつで正当性を判断したい

Posted at

環境

  • php7.0
  • symfony2.8

やりたいこと

slackのoutgoing webhookから送られてくるリクエストのトークンが
正しいかどうかをコントローラでリクエストを受ける前に行いたい。

↓イメージ

HogeController
/**
 * リクエストの正当性を事前に確かめておきたい
 * 
 * @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.yml
parameters:
    database_host: mysql
    .
    .
    .
    out_going_webhook_tokens:
        client1: xxxx
        client2: xxxx

チェックしたいコントローラにtokenチェックを行うかどうかを判別させるinterfaceを持たせる

interface作成

SlackWebhookTokenAuthenticated.php
<?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);
    }
}

イベントリスナー作成

SlackWebhookTokenListener.php
<?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.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の補完が便利すぎて震える。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3