Как я могу получить токен безопасности для любого пользователя, а не только того, кто в настоящий момент входит в систему?
Я хотел бы иметь возможность вызвать isGranted () для пользователя, извлеченного из базы данных
isGranted()
поступает из службы безопасности, поэтому было бы сложно / не нужно использовать это для получения Ролей без корректировки состояния сеанса.
Не поймите меня неправильно, это определенно возможно … Это будет работать, например:
public function strangeAction() { // Get your User, however you normally get it $user = $userRepository->find($id); // Save the current token so you can put it back later $previousToken = $this->get("security.context")->getToken(); // Create a new token $token = new UsernamePasswordToken($user, null, "main", $user->getRoles()); // Update the security context with the new token $this->get("security.context")->setToken($token); // Now you have access to isGranted() if ($this->get("security.context")->isGranted("ROLE_SOMETHING")) { /* Do something here */ } // Don't forget to reset the token! $this->get("security.context")->setToken($previousToken); }
… но это действительно бессмысленно.
На самом деле вам не нужен токен. Гораздо лучший способ сделать это – добавить метод isGranted()
в свой пользовательский объект:
// Namespace\YourBundle\Entity\User.php class User { ... public function isGranted($role) { return in_array($role, $this->getRoles()); } ... }
Теперь вы можете получить эти роли в своих контроллерах:
public function notSoStrangeAction() { // Get your User, however you normally get it $user = $userRepository->find($id); // Find out if that User has a Role associated to it if ($user->isGranted("ROLE_SOMETHING")) { /* Do something here */ } }
У меня были те же требования некоторое время назад. Поэтому я реализовал это сам. Поскольку вам требуется информация о иерархии из контейнера, не рекомендуется распространять пользовательский объект с этой функциональностью.
// first check if the role is inside the user roles of the user // if not then check for each user role if it is a master role of the check role public function isGranted($user, $checkrole){ $userroles = $user->getRoles(); if (in_array($checkrole, $userroles)){return true;} foreach ($userroles as $userrole){ if ($this->roleOwnsRole($userrole, $checkrole)){return true;} } return false; } // recursively loop over the subroles of the master to check if any of them are // the suggested slave role. If yes then the masterrole is a master and has // the same grants as the slave. private function roleOwnsRole($masterRole, $slaveRole, $checkvalidityroles=true, $hierarchy=null) { if ($hierarchy===null){$hierarchy = $this->container->getParameter('security.role_hierarchy.roles');} if ($masterRole === $slaveRole){ return false; } if($checkvalidityroles && (!array_key_exists($masterRole, $hierarchy) || !array_key_exists($slaveRole, $hierarchy))){ return false; } $masterroles = $hierarchy[$masterRole]; if(in_array($slaveRole, $masterroles)){ return true; }else{ foreach($masterroles as $masterrolerec){ if ($this->roleOwnsRole($masterrolerec, $slaveRole, false, $hierarchy)){return true;} } return false; } }
Я думаю, что лучший способ – вызвать AccessDecisionManager
вручную – например, $securityContext->isGranted()
, но для текущего пользователя. Это тоже хорошо, если вы используете Symfony Voters для определения доступа.
$token = new UsernamePasswordToken($userObject, 'none', 'main', $userObject->getRoles()); $hasAccess = $this->get('security.access.decision_manager')->decide($token, array('voter'), $optionalObjectToCheckAccessTo);