🎻

[Symfony] エンティティ(リソース)の所有者以外のユーザーからのアクセスを禁止する

2020/04/14に公開

「エンティティの詳細表示は誰でもアクセスできるけど、編集画面はエンティティの所有者ユーザーでログインしていないとアクセス不可」といった要件はよくあります。

これをSymfonyで実現する場合の方法について説明してみます。

愚直な方法

普通にコントローラのアクションメソッドの先頭にif文を書けば対応できますね。真っ先に思いつくのはこの方法でしょう。

/**
 * @Route("/foo", name="foo_")
 */
class FooController extends AbstractController
{
    // ...

    /**
     * @Route("/{id}/edit", name="edit", methods={"GET","POST"})
     */
    public function edit(Foo $foo)
    {
        if ($foo->getUser() != $this->getUser()) {
            throw new AccessDeniedHttpException();
        }

        // ...
    }
}

手軽な方法

@Security アノテーションを使うと、もう少しスッキリ書けます。

参考: https://symfony.com/doc/4.2/best_practices/security.html#using-expressions-for-complex-security-restrictions

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;

/**
 * @Route("/foo", name="foo_")
 */
class FooController extends AbstractController
{
    // ...

    /**
     * @Route("/{id}/edit", name="edit", methods={"GET","POST"})
     * @Security("foo.getUser() == user")
     */
    public function edit(Foo $foo)
    {
        // ...
    }
}

スッキリしてていい感じですね。

ただし、 @Security アノテーションを使うためには symfony/expression-language がインストールされている必要があります。

symfony/expression-languageが入っていない状態で @Security を使おうとすると以下のエラーになります。

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

まとめ

  • 「エンティティの詳細表示は誰でもアクセスできるけど、編集画面はエンティティの所有者ユーザーでログインしていないとアクセス不可」という要件をSymfonyで実装する場合、コントローラのアクションメソッドにif文を書いてもいいけど、@Security アノテーション を使うとスッキリ書けてよい
  • ただし symfony/expression-language がインストールされている必要があるので要注意
GitHubで編集を提案

Discussion