<?php
namespace App\Backoffice\BackofficeUser;
use App\Backoffice\Enum\BackofficeFeatureAccessEnum;
use AppBundle\Entity\User;
use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Security;
/**
* Voter to allow access to Backoffice
*/
class BackofficeUserVoter extends Voter
{
// This attribute is set on access_control in security.yml
private const BACKOFFICE = 'BACKOFFICE';
public const BACKOFFICE_CAN_SWITCH = 'BACKOFFICE_CAN_SWITCH';
private Security $security;
private AccessDecisionManagerInterface $accessDecisionManager;
public function __construct(Security $security, AccessDecisionManagerInterface $accessDecisionManager)
{
$this->security = $security;
$this->accessDecisionManager = $accessDecisionManager;
}
/**
* @inheritDoc
*/
protected function supports($attribute, $subject): bool
{
return in_array($attribute, [
self::BACKOFFICE,
self::BACKOFFICE_CAN_SWITCH,
], true);
}
/**
* @inheritDoc
*/
protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool
{
$user = $token->getUser();
// Backoffice users and real users use instance of User
// Later Backoffice users will have their own entity
if (!$user instanceof User) {
return false;
}
switch ($attribute) {
case self::BACKOFFICE:
return $this->haveAccess($token);
case self::BACKOFFICE_CAN_SWITCH:
return $this->canSwitch($token);
default:
return false;
}
}
/**
* @param TokenInterface $token
* @return bool
*/
private function haveAccess(TokenInterface $token): bool
{
// Vote when a Backoffice user has switched to a User
// Note: the Security service can grant access only on current user,
// so we need to use the AccessDecisionManager instead (used by Security)
if ($token instanceof SwitchUserToken) {
return $this->accessDecisionManager->decide($token->getOriginalToken(), [User::ROLE_BACKOFFICE]);
}
return $this->security->isGranted(User::ROLE_BACKOFFICE);
}
/**
* @param TokenInterface $token
* @return bool
*/
private function canSwitch(TokenInterface $token): bool
{
if (!$this->haveAccess($token)) {
return false;
}
/**
* Already switched
* @see \Symfony\Component\Security\Http\Firewall\SwitchUserListener::attemptSwitchUser
*/
if ($this->security->isGranted('ROLE_PREVIOUS_ADMIN')) {
return false;
}
return $this->security->isGranted(BackofficeFeatureAccessEnum::BO_SWITCH_USER);
}
}