LoginSignup
1
0

More than 5 years have passed since last update.

Symfonyで特定のControllerのみ署名認証する

Posted at

背景・動機

既存のSymfonyプロジェクトに署名付きのREST APIを追加することになり、他の処理に影響を与えないよう特定のControllerのみ追加する必要があったため、備忘録を兼ねて実装方法を投稿します。

環境

Symfony 3.0.1
PHP 7.0.2

手順

ざっくりと以下のような手順になります。

  1. 署名認証したいControllerに設定するインターフェースを追加。
  2. イベントリスナーを作成しサービスコンテナに登録。
  3. イベントリスナー内でControllerを参照し、インターフェースを見て署名認証を行う。
  4. 署名認証に失敗すれば例外をスロー。

1. 署名認証したいController用のインターフェースを作成

空のインターフェースでOKです。
署名認証が必要なControllerを特定する目的で利用します。

interface SignatureAuthenticatedController {}

2. イベントリスナーを作成

以下のようなイベントリスナーを作成します。

class SignatureListener {
  public function onKernelController(FilterControllerEvent $event) {
    // Controllerを取得
    $controller = $event->getController();
    if (!is_array($controller)) {
      return;
    }
    // Controllerがインターフェースを実装しているかチェック
    if ($controller[0] instanceof SignatureAuthenticatedController) {
      // Requestを取得
      $request = $event->getRequest();
      // ヘッダーから署名を取得
      $signature = $request->headers->get('x-hogehoge-signature');
      // Requestを使ってダイジェスト値を計算
      // 署名の方法については適宜実装してください
      $canonicalString = $request->getMethod() . "\n" .
                         $request->getHost() . "\n" .
                         $request->getPathInfo() . "\n" .
                         $request->getQueryString() . "\n" .
                         $request->getContent();
      $digest = hash_hmac('sha256', base64_encode($canonicalString), 'secret');
      // ダイジェスト値と署名が違っていたら例外をスロー
      if ($signature !== $digest) {
        throw new AccessDeniedHttpException('Invalid signature.');
      }
    }
  }
}

3. services.ymlにリスナーを追加

app.action_listener:
  class: AppBundle\EventListener\SignatureListener
  tags:
    - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
    - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }

4. 署名で保護したいControllerにインターフェースを実装

class SecretController extends Controller implements SignatureAuthenticatedController {
}

今回はControllerとExceptionのイベントリスナーを利用しましたが、他にも色々あるようですのでいつか試してみたいと思います。
もし似たような問題を抱えている方がおられましたら、割と簡単な手順で実装できますので、お試しください。

1
0
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
1
0