<?php
// src/Security/UserVoter.php
namespace App\Security;
use App\Entity\User;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
/**
* @see https://symfony.com/doc/current/security/voters.html
*/
class UserVoter extends Voter
{
// these strings are made up: you can use anything
const VIEW = 'view';
const EDIT = 'edit';
/** @var Security */
private $security;
public function __construct(Security $security)
{
$this->security = $security;
}
/**
* Determine if the voter supports given attribute and subject
*
* @param string $attribute
* @param $subject
*
* @return bool
*/
protected function supports($attribute, $subject)
{
// if the attribute isn't one we support, return false
if (!in_array($attribute, [self::VIEW, self::EDIT])) {
return false;
}
// only vote on User objects inside this voter
if (!$subject instanceof User) {
return false;
}
return true;
}
/**
* Vote to grant (return true) or deny (return false) access
*
* @param string $attribute
* @param User $subject
* @param TokenInterface $token
*
* @return bool
*
* @throws \LogicException when an invalid attribute is provided
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
$currentUser = $token->getUser();
if (!$currentUser instanceof User) {
// the user must be logged in; if not, deny access
return false;
}
// Admins can do anything! The power!
if ($this->security->isGranted('ROLE_ADMIN')) {
return true;
}
switch ($attribute) {
case self::VIEW:
return $this->canView($subject, $currentUser);
case self::EDIT:
return $this->canEdit($subject, $currentUser);
}
throw new \LogicException('This code should not be reached!');
}
private function canView(User $accessedUser, User $currentUser)
{
// if they can edit, they can view
if ($this->canEdit($accessedUser, $currentUser)) {
return true;
}
// the Post object could have, for example, a method isPrivate()
// that checks a boolean $private property
// return !$accessedUser->isPrivate();
return false;
}
private function canEdit(User $accessedUser, User $currentUser)
{
// this assumes that the data object has a getOwner() method
// to get the entity of the user who owns this data object
return $currentUser === $accessedUser;
}
}