@@ -63,43 +63,72 @@ Setup: Checking for Access in a Controller
6363
6464Suppose you have a ``Post `` object and you need to decide whether or not the current
6565user can *edit * or *view * the object. In your controller, you'll check access with
66- code like this::
66+ code like this:
6767
68- // src/Controller/PostController.php
68+ .. configuration-block ::
6969
70- // ...
71- class PostController extends AbstractController
72- {
73- #[Route('/posts/{id}', name: 'post_show')]
74- public function show($id): Response
75- {
76- // get a Post object - e.g. query for it
77- $post = ...;
70+ .. code-block :: php-attributes
7871
72+ // src/Controller/PostController.php
73+
74+ // ...
75+ use Symfony\Component\Security\Http\Attribute\IsGranted;
76+
77+ class PostController extends AbstractController
78+ {
79+ #[Route('/posts/{id}', name: 'post_show')]
7980 // check for "view" access: calls all voters
80- $this->denyAccessUnlessGranted('view', $post);
81+ #[IsGranted('show', 'post')]
82+ public function show(Post $post): Response
83+ {
84+ // ...
85+ }
8186
82- // ...
87+ #[Route('/posts/{id}/edit', name: 'post_edit')]
88+ // check for "edit" access: calls all voters
89+ #[IsGranted('edit', 'post')]
90+ public function edit(Post $post): Response
91+ {
92+ // ...
93+ }
8394 }
8495
85- #[Route('/posts/{id}/edit', name: 'post_edit')]
86- public function edit($id): Response
96+ .. code-block :: php
97+
98+ // src/Controller/PostController.php
99+
100+ // ...
101+
102+ class PostController extends AbstractController
87103 {
88- // get a Post object - e.g. query for it
89- $post = ...;
104+ #[Route('/posts/{id}', name: 'post_show')]
105+ public function show(Post $post): Response
106+ {
107+ // check for "view" access: calls all voters
108+ $this->denyAccessUnlessGranted('view', $post);
90109
91- // check for "edit" access: calls all voters
92- $this->denyAccessUnlessGranted('edit', $post);
110+ // ...
111+ }
93112
94- // ...
113+ #[Route('/posts/{id}/edit', name: 'post_edit')]
114+ public function edit(Post $post): Response
115+ {
116+ // check for "edit" access: calls all voters
117+ $this->denyAccessUnlessGranted('edit', $post);
118+
119+ // ...
120+ }
95121 }
96- }
97122
98- The ``denyAccessUnlessGranted() `` method (and also the ``isGranted() `` method)
123+ The ``#[IsGranted()] `` attribute or `` denyAccessUnlessGranted() `` method (and also the ``isGranted() `` method)
99124calls out to the "voter" system. Right now, no voters will vote on whether or not
100125the user can "view" or "edit" a ``Post ``. But you can create your *own * voter that
101126decides this using whatever logic you want.
102127
128+ .. versionadded :: 6.2
129+
130+ The ``#[IsGranted()] `` attribute was introduced in Symfony 6.2.
131+
103132Creating the custom Voter
104133-------------------------
105134
@@ -418,3 +447,35 @@ must implement the :class:`Symfony\\Component\\Security\\Core\\Authorization\\Ac
418447 // ...
419448 ;
420449 };
450+
451+ .. _security-voters-change-message-and-status-code :
452+
453+ Changing the message and status code returned
454+ ---------------------------------------------
455+
456+ By default, the ``#[IsGranted] `` attribute will throw a
457+ :class: `Symfony\\ Component\\ Security\\ Core\\ Exception\\ AccessDeniedException `
458+ and return an http **403 ** status code with **Access Denied ** as message.
459+
460+ However, you can change this behavior by specifying the message and status code returned::
461+
462+ // src/Controller/PostController.php
463+
464+ // ...
465+ use Symfony\Component\Security\Http\Attribute\IsGranted;
466+
467+ class PostController extends AbstractController
468+ {
469+ #[Route('/posts/{id}', name: 'post_show')]
470+ #[IsGranted('show', 'post', 'Post not found', 404)]
471+ public function show(Post $post): Response
472+ {
473+ // ...
474+ }
475+ }
476+
477+ .. tip ::
478+
479+ If the status code is different than 403, an
480+ :class: `Symfony\\ Component\\ HttpKernel\\ Exception\\ HttpException `
481+ will be thrown instead.
0 commit comments