🎻
[Symfony] エンティティ(リソース)の所有者以外のユーザーからのアクセスを禁止する
「エンティティの詳細表示は誰でもアクセスできるけど、編集画面はエンティティの所有者ユーザーでログインしていないとアクセス不可」といった要件はよくあります。
これを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
アノテーションを使うと、もう少しスッキリ書けます。
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 がインストールされている必要があるので要注意
Discussion