我是Symfony2的初学者,虽然已经开发了PHP多年(ZF1,ZF2,CakePHP)。
在SF2中,根据站点本身的文档,我有以下场景:
security:
access_control:
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: ROLE_ADMIN }
我需要手动添加每个"路径"和#34;角色"可以访问这个"路径"。 我怎么能动态地这样做? 就像Yii2上的RBAC一样:
是否有任何现成的Bundle或SF2自己的文档允许这样做?作为假设的例子:
security:
access_control:
type: dynamically
PS:对不起主持人,我不知道怎么问这个。请帮我改进我的问题。
答案 0 :(得分:1)
如果您想更轻松地添加角色,可以使用annotations。
您的问题要求动态安全,这很复杂。在缓存预热阶段编译路由和所有角色。因此,为此,您首先需要存储动态值。数据库将是一个很好的选择。在这里,我只展示如何检查角色,我将留给你的实际角色操作。
最简单的方法是将授权检查程序注入您的控制器。
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();
}
// ...
}
如果你想在多个控制器中使用上面的代码,那么你也可以创建一个voter:
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。
答案 1 :(得分:1)
您可以像这样动态管理角色/路线关系:
您在内核上创建一个侦听器
<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")
}
}
由于此侦听器将始终在任何控制器之前调用,因此请考虑创建缓存系统