src/Security/Voter/UserVoter.php line 13

Open in your IDE?
  1. <?php
  2. namespace App\Security\Voter;
  3. use App\Entity\Role;
  4. use App\Entity\User;
  5. use App\Service\UserService;
  6. use LogicException;
  7. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  8. use Symfony\Component\Security\Core\Authorization\Voter\Voter;
  9. use Symfony\Component\Security\Core\Security;
  10. class UserVoter extends Voter
  11. {
  12.     public const VIEW_USER 'view_user';
  13.     public const EDIT_USER 'edit_user';
  14.     public const LIST_USERS 'list_users';
  15.     public const CREATE_USER 'create_user';
  16.     public const CHANGE_PASS 'change_pass';
  17.     public const LOCK_USER 'lock_user';
  18.     public const UNLOCK_USER 'unlock_user';
  19.     public const DELETE_USER 'delete_user';
  20.     /** @var UserService $userService */
  21.     private $userService;
  22.     /**
  23.      * UserVoter constructor.
  24.      * @param UserService $userService
  25.      */
  26.     public function __construct(UserService $userService)
  27.     {
  28.         $this->userService $userService;
  29.     }
  30.     /**
  31.      * @inheritDoc
  32.      */
  33.     protected function supports($attribute$subject): bool
  34.     {
  35.         // if the attribute isn't one we support, return false
  36.         if (
  37.             !in_array($attribute, [
  38.                 self::VIEW_USER,
  39.                 self::EDIT_USER,
  40.                 self::LIST_USERS,
  41.                 self::CREATE_USER,
  42.                 self::CHANGE_PASS,
  43.                 self::LOCK_USER,
  44.                 self::UNLOCK_USER,
  45.                 self::DELETE_USER
  46.             ])
  47.         ) {
  48.             return false;
  49.         }
  50.         // only vote on User objects inside this voter
  51.         if (!$subject instanceof User) {
  52.             return false;
  53.         }
  54.         return true;
  55.     }
  56.     /**
  57.      * @inheritDoc
  58.      */
  59.     protected function voteOnAttribute($attribute$subjectTokenInterface $token): bool
  60.     {
  61.         $user $token->getUser();
  62.         if (!$user instanceof User) {
  63.             // the user must be logged in; if not, deny access
  64.             return false;
  65.         }
  66.         // you know $subject is a User object, thanks to supports
  67.         /** @var User $userSubject */
  68.         $userSubject $subject;
  69.         switch ($attribute) {
  70.             case self::CREATE_USER:
  71.                 return $this->canCreate($user);
  72.             case self::VIEW_USER:
  73.                 return $this->canView($userSubject$user);
  74.             case self::EDIT_USER:
  75.                 return $this->canEdit($userSubject$user);
  76.             case self::LIST_USERS:
  77.                 return $this->canList($user);
  78.             case self::CHANGE_PASS:
  79.                 return $this->canChangePass($userSubject$user);
  80.             case self::LOCK_USER:
  81.                 return $this->canLock($userSubject$user);
  82.             case self::UNLOCK_USER:
  83.                 return $this->canUnlock($userSubject$user);
  84.             case self::DELETE_USER:
  85.                 return $this->canDelete($userSubject$user);
  86.         }
  87.         throw new LogicException('This code should not be reached!');
  88.     }
  89.     /**
  90.      * @param User $userSubject
  91.      * @param User $user
  92.      * @return bool
  93.      */
  94.     private function canView(User $userSubjectUser $user): bool
  95.     {
  96.         // if they can edit, they can view
  97.         if ($this->canEdit($userSubject$user)) {
  98.             return true;
  99.         }
  100.         return false;
  101.     }
  102.     /**
  103.      * @param User $user
  104.      * @return bool
  105.      */
  106.     private function canCreate(User $user): bool
  107.     {
  108.         return $this->userService->isAdmin($user);
  109.     }
  110.     /**
  111.      * @param User $userSubject
  112.      * @param User $user
  113.      * @return bool
  114.      */
  115.     private function canEdit(User $userSubjectUser $user): bool
  116.     {
  117.         if ($user === $userSubject) {
  118.             // this assumes that the data object has a getId() method
  119.             // to get the entity of the user who owns this data object
  120.             return true;
  121.         }
  122.         if ($userSubject->isSuperAdmin()) {
  123.             return false;
  124.         }
  125.         return $this->canByRoles($userSubject$user);
  126.     }
  127.     /**
  128.      * @param User $user
  129.      * @return bool
  130.      */
  131.     private function canList(User $user): bool
  132.     {
  133.         return $this->userService->isAdmin($user);
  134.     }
  135.     /**
  136.      * @param User $userSubject
  137.      * @param User $user
  138.      * @return bool
  139.      */
  140.     private function canChangePass(User $userSubjectUser $user): bool
  141.     {
  142.         return $user === $userSubject;
  143.     }
  144.     /**
  145.      * @param User $userSubject
  146.      * @param User $user
  147.      * @return bool
  148.      */
  149.     private function canUnlock(User $userSubjectUser $user): bool
  150.     {
  151.         if ($this->canLock($userSubject$user)) {
  152.             return true;
  153.         }
  154.         return false;
  155.     }
  156.     /**
  157.      * @param User $userSubject
  158.      * @param User $user
  159.      * @return bool
  160.      */
  161.     private function canDelete(User $userSubjectUser $user): bool
  162.     {
  163.         if ($this->canLock($userSubject$user)) {
  164.             return true;
  165.         }
  166.         return false;
  167.     }
  168.     /**
  169.      * @param User $userSubject
  170.      * @param User $user
  171.      * @return bool
  172.      */
  173.     private function canLock(User $userSubjectUser $user): bool
  174.     {
  175.         if ($userSubject->isSuperAdmin() || $user === $userSubject) {
  176.             return false;
  177.         }
  178.         return $this->canByRoles($userSubject$user);
  179.     }
  180.     /**
  181.      * @param User $userSubject
  182.      * @param User $user
  183.      * @return bool
  184.      */
  185.     private function canByRoles(User $userSubjectUser $user): bool
  186.     {
  187.         // logged user is admin of userSubject
  188.         /** @var Role $role */
  189.         foreach ($user->getRolesAsObject() as $role) {
  190.             if ($role->getChildren()->count()) {
  191.                 return $this->userService->isSubordinate($user$userSubject);
  192.             }
  193.         }
  194.         return false;
  195.     }
  196. }