Я новичок в Symfony2, хотя уже много лет разрабатываю с PHP (ZF1, ZF2, CakePHP).
В SF2 у меня следующий сценарий, согласно документации самого сайта:
security:
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_ADMIN }
Мне нужно вручную добавить каждый «путь» и «роли», которые могут получить доступ к этому «пути».
Как я могу сделать это динамически?
Как RBAC на Yii2:
Есть ли готовый комплект или что-то в собственной документации SF2, позволяющее это сделать? В качестве гипотетического примера:
security:
access_control:
type: dynamically
PS: Простите модераторы, я не знаю, как это спросить. Пожалуйста, помогите мне улучшить мой вопрос.
Если вы хотите упростить добавление ролей, вы можете использовать аннотации.
Ваш вопрос требует динамической безопасности, которая сложна. Маршруты и все роли компилируются на этапе прогрева кэша. Итак, чтобы это работало, вам сначала нужно сохранить динамические значения. База данных будет хорошим вариантом для этого. Здесь я только покажу, как проверять роли, фактическую манипуляцию ролями, которую я оставлю вам.
Самый простой способ — внедрить проверку авторизации в ваш контроллер.
services:
acme_controller:
class: "AcmeDemoBundle\Controller"arguments: ["@security.authorization_checker"]
Затем проверьте роли в действии (ях):
public function __construct(AuthorizationCheckerInterface $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
}
public function listAction()
{
$role = /* load your role here */;
if (false === $this->authorizationChecker->isGranted($role)) {
throw new AccessDeniedException();
}
// ...
}
Выше приведено дублирование кода, если вы хотите его во многих контроллерах, так что вы также можете создать избиратель:
services:
acme.route.voter:
class: AcmeDemoBundle\RouteVoter
arguments:
- @security.role_hierarchy
public: false
tags:
- { name: security.voter, priority: 300 }
Пример:
public function __construct ( RoleHierarchyInterface $roleHierarchy )
{
$this->roleVoter = new RoleHierarchyVoter( $roleHierarchy );
}
public function vote ( TokenInterface $token, $object, array $attributes )
{
if ( !$object instanceof Request ) {
return VoterInterface::ACCESS_ABSTAIN;
}
$requestUri = $object->getPathInfo();
if ( isset($this->votes[ $requestUri ]) ) {
return $this->votes[ $requestUri ];
}
$roles = /* load your roles */;
return $this->votes[ $requestUri ] = $this->roleVoter->vote( $token, $object, $roles );
}
Другим методом будет заменить router
сервис с вашей собственной реализацией. Это подход, принятый моим CMF Bundle.
Вы можете динамически управлять отношением роли / маршрута следующим образом:
Вы создаете слушатель на ядре
<service id="toto.security.controller_listener" class="Administration\SecurityBundle\EventListener\SecurityListener">
<tag name="kernel.event_listener" event="kernel.controller" method="onKernelController" />
<argument type="service" id="service_container" />
</service>
и после того, как в слушателе вы реализуете этот метод
public function onKernelController(FilterControllerEvent $event)
{
$controller = $event->getController();
if (!is_array($controller)) {
return;
}$request = $event->getRequest();
$baseUrl = $request->getBaseUrl();
$requestUri = $request->getRequestUri();
$route = str_replace($baseUrl, "", $requestUri);
//you put your check logic
//you can implement a relation beetween routes and roles/ users in database etc. you got the entire control on what you do
if(!$this->accessMananager->isGrantAccess(User $user, $route)){
throw new AccessDeniedException("blah blah blah")
}}
так как этот слушатель всегда будет вызываться перед любым вашим контроллером, рассмотрите возможность создания системы кеша