Skip to content

Commit 757e159

Browse files
committed
feature symfony#5926 Update voter section of best practices (WouterJ)
This PR was merged into the 2.8 branch. Discussion ---------- Update voter section of best practices | Q | A | --- | --- | Doc fix? | yes | New docs? | yes | Applies to | 2.8+ | Fixed tickets | symfony#4389, symfony#5728 Commits ------- 68da041 Update voter section of best practices
2 parents bb1a9b7 + 68da041 commit 757e159

File tree

1 file changed

+45
-15
lines changed

1 file changed

+45
-15
lines changed

Diff for: best_practices/security.rst

+45-15
Original file line numberDiff line numberDiff line change
@@ -264,37 +264,66 @@ the same ``getAuthorEmail`` logic you used above:
264264
265265
namespace AppBundle\Security;
266266
267-
use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter;
267+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
268+
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
269+
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
268270
use Symfony\Component\Security\Core\User\UserInterface;
271+
use AppBundle\Entity\Post;
269272
270-
// AbstractVoter class requires Symfony 2.6 or higher version
271-
class PostVoter extends AbstractVoter
273+
// Voter class requires Symfony 2.8 or higher version
274+
class PostVoter extends Voter
272275
{
273276
const CREATE = 'create';
274277
const EDIT = 'edit';
275278
276-
protected function getSupportedAttributes()
279+
/**
280+
* @var AccessDecisionManagerInterface
281+
*/
282+
private $decisionManager;
283+
284+
public function __construct(AccessDecisionManagerInterface $decisionManager)
277285
{
278-
return array(self::CREATE, self::EDIT);
286+
$this->decisionManager = $decisionManager;
279287
}
280288
281-
protected function getSupportedClasses()
289+
protected function supports($attribute, $subject)
282290
{
283-
return array('AppBundle\Entity\Post');
291+
if (!in_array($attribute, array(self::CREATE, self::EDIT))) {
292+
return false;
293+
}
294+
295+
if (!$subject instanceof Post) {
296+
return false;
297+
}
298+
299+
return true;
284300
}
285301
286-
protected function isGranted($attribute, $post, $user = null)
302+
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
287303
{
304+
$user = $token->getUser();
305+
/** @var Post */
306+
$post = $subject; // $subject must be a Post instance, thanks to the supports method
307+
288308
if (!$user instanceof UserInterface) {
289309
return false;
290310
}
291311
292-
if ($attribute === self::CREATE && in_array('ROLE_ADMIN', $user->getRoles(), true)) {
293-
return true;
294-
}
295-
296-
if ($attribute === self::EDIT && $user->getEmail() === $post->getAuthorEmail()) {
297-
return true;
312+
switch ($attribute) {
313+
case self::CREATE:
314+
// if the user is an admin, allow them to create new posts
315+
if ($this->decisionManager->decide($token, array('ROLE_ADMIN'))) {
316+
return true;
317+
}
318+
319+
break;
320+
case self::EDIT:
321+
// if the user is the author of the post, allow them to edit the posts
322+
if ($user->getEmail() === $post->getAuthorEmail()) {
323+
return true;
324+
}
325+
326+
break;
298327
}
299328
300329
return false;
@@ -310,6 +339,7 @@ To enable the security voter in the application, define a new service:
310339
# ...
311340
post_voter:
312341
class: AppBundle\Security\PostVoter
342+
arguments: ['@security.access.decision_manager']
313343
public: false
314344
tags:
315345
- { name: security.voter }
@@ -337,7 +367,7 @@ via the even easier shortcut in a controller:
337367
*/
338368
public function editAction($id)
339369
{
340-
$post = // query for the post ...
370+
$post = ...; // query for the post
341371
342372
$this->denyAccessUnlessGranted('edit', $post);
343373

0 commit comments

Comments
 (0)