🎻

[Symfony] @IsGranted("ROLE_HOGE")をPOSTリクエスト時のみ適用する方法

2020/12/23に公開

はじめに

Symfony Advent Calendar 2020 の23日目の記事です!🎄🌙

昨日は @polidog さんの それでも僕は@Templateアノテーションを使いたい でした✨

一昨日の僕の記事

[Symfony] @Templateアノテーションを使わないほうがいい理由

に対するアンサーエントリー的な内容で嬉しかったです😂

僕自身、@Tempalte アノテーションに起因して発生したトラブルの根本原因を深追いする熱意と気力がなくて詳細を知るのを諦めてたところだったので大変ありがたい内容でした!

ちなみに、僕はよく TwitterにもSymfonyネタを呟いている ので、よろしければぜひ フォローしてやってください🕊🤲

やりたいこと

さて本題です。

@IsGranted() アノテーションを使えば、コントローラの各アクションメソッドへのリクエストをROLEベースで簡単に制限することができます。

/**
 * @Route("/foo/index", name="foo_index", methods={"GET", "POST"})
 * @IsGranted("ROLE_WRITE")
 */
public function index(Request $request)
{
    // 略
}

この例では、 foo_index アクションはGETリクエストとPOSTリクエストを許可していますが、 ROLE_WRITE を持たないユーザーからのリクエストはGETでもPOSTでもすべて弾かれます。

では、GETリクエストは誰でもできるけど、POSTリクエストだけは ROLE_WRITE を持っていないとダメ という仕様にしたい場合はどうすればよいでしょうか?

この記事ではそのやり方を解説します。

こちらの過去記事も合わせてどうぞ。

[Symfony] Security Voterを使って「リソースの所有者でないと編集不可」を実装してみよう

やり方

といってもやり方はとても簡単で、 **@IsGranted() の代わりに @Security() を使うだけで簡単に実現できます👍

@Security() アノテーションは引数に expression を取るので、@IsGranted() よりも複雑なロジックを書くことができます。

「POSTリクエスト時のみ ROLE_WRITE を要求する」という今回の例であれば、以下のような記述で実現できます。

/**
 * @Route("/foo/index", name="foo_index", methods={"GET", "POST"})
 * @Security("request.getMethod() === 'GET' or is_granted('ROLE_WRITE')")
 */
public function index(Request $request)
{
    // 略
}

symfony/expression-language に依存している機能なので、

$ composer require symfony/expression-language

しておかないと、以下のようにエラーになるのでご注意ください。

To use the @Security tag, you need to use the Security component 2.4 or newer and install the ExpressionLanguage component.

expression の書き方の詳細については symfony/expression-language のドキュメントをご参照ください。

ちなみに、 @IsGranted() の場合も同様ですが、権限が足りなかった場合のデフォルトの動作は「302でログインページにリダイレクト」なので、403でエラーにしたい場合は引数で明示してあげる必要があります✋

/**
 * @Security("request.getMethod() === 'GET' or is_granted('ROLE_WRITE')", statusCode=403)
 */

おわりに

というわけで、小ネタでしたが、Symfonyで @IsGranted("ROLE_HOGE") をPOSTリクエスト時のみ適用する方法について解説してみました。お役に立てば幸いです。

Symfony Advent Calendar 2020、明日は @77web さんです!お楽しみに!

GitHubで編集を提案

Discussion