【问题标题】:Reusing security rules defined by @Security annotation重用@Security注解定义的安全规则
【发布时间】:2015-11-10 10:14:35
【问题描述】:

@Security注解定义的权限时,是否可以检查用户是否可以从控制器本身外部访问控制器?
例如:
如果我们有这样的控制器:

/**
* @Security("has_role('ROLE_ADMIN')")
*/
function myController() { ... }

我们可以像这样执行授权检查吗:

[伪代码]

    // get an object representation of `@Security` annotation
    $controllerSecurity = $this->get('some_magic_service')
        ->getSecurityForController('Bundle:Controller:myController');
   // check if a current user is granted
   if ($controllerSecurity->isGranted($user)) { ... }

[/伪代码]

我认为 Symfony 核心安全组件在检查控制器授权时会做类似的事情......

【问题讨论】:

    标签: php security symfony


    【解决方案1】:

    与其尝试检查每个路由/控制器的访问权限,不如简单地不要为那些无权访问的人显示您的菜单项。创建一个返回用户类型的服务类。

    services.yml

    app_security.access.manager:
        class: AppBundle\Services\SecurityAccessManager
        arguments: [@security.authorization_checker,@security.token_storage]
    

    SecurityAccessManager.php

    <?php
    
    
    namespace AppBundle\Services;
    
    
    use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
    use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
    
    class SecurityAccessManager
    {
        private $authorizationChecker;
        private $tokenStorage;   
    
        public function __construct(AuthorizationChecker $authorizationChecker,TokenStorage $tokenStorage)
        {
            $this->authorizationChecker = $authorizationChecker;
            $this->tokenStorage = $tokenStorage;
    
        }
    
    
        public function getUser()
        {
            return $this->tokenStorage->getToken()->getUser();
        }
    
    
        public function isAdmin()
        {
            if($this->authorizationChecker->isGranted('ROLE_ADMIN') !== true) {
                return false;
            } else {
                return true;
            }
        }  
    
    }
    

    然后在您的菜单生成器中,您需要注入该类并检查权限:

    这是一个带有 KNP 菜单的示例:

    app.menu.builder
            class: AppBundle\Menu\MenuBuilder
            arguments: [@knp_menu.factory,@medapp_security.access.manager]
    

    还有菜单生成器

    class MenuBuilder extends ContainerAware
    {
        /**
         * @var FactoryInterface
         */
        private $factoryInterface; 
        private $securityAccessManager;
    
       public function __construct(FactoryInterface $factoryInterface, SecurityAccessManager $securityAccessManager)
        {  
            $this->factoryInterface = $factoryInterface;   
            $this->securityAccessManager = $securityAccessManager;
    
        }
    

    ...

    $menu->addChild('user link',..);
    if ($this->securityAccessManager->isAdmin())     $menu->addChild('admin link',..);
    

    【讨论】:

    • 我最终做了同样的事情 =) 将 @service_container 注入 MenuBuilder 服务并在那里实现快捷方式 isGranted 方法就足够了:public function isGranted($attributes) { return $this-&gt;container-&gt;get('security.authorization_checker')-&gt;isGranted($attributes); }
    • 是的,但如果你以后改变你的角色,你必须在任何地方都改变它。但是,如果您每次都使用自定义类来检查它,如果由于某种原因您稍后确实更改了角色,您只需从自定义类中更改它。取决于您要构建的内容。
    【解决方案2】:

    当调用 isGranted() 时,它只使用三个标准 Symfony2 投票者(+自定义投票者,如果你定义了它):AuthenticatedVoterExpressionVoter 和 RoleHierarchyVoter

    AuthenticatedVoter 只检查当前令牌的身份验证级别:IS_AUTHENTICATED_FULLYIS_AUTHENTICATED_REMEMBEREDIS_AUTHENTICATED_ANONYMOUSLY

    所以如果你不使用 Roles,默认只有 AuthenticatedVoter 返回结果。

    如果您想为控制器的任何操作定义自定义权限,您可以使用Voters。我认为它最适合您的任务。

    然后您可以在任何操作的顶部调用 Voters,如下所示:

    public function indexAction()
    {
        $this->denyAccessUnlessGranted('permission', $entity);
        // your code
    }
    

    但如果你想对应用的整个部分应用安全限制,你可以使用access_control

    【讨论】:

    • 谢谢。我需要检查用户是否可以访问控制器本身之外的控制器,并且不重复控制器中定义的所有访问规则。我需要它来在构建菜单时检查菜单项的访问。我只有一个路由名称和一个用户对象,应该检查用户是否可以访问控制器(可以通过路由名称轻松检索)
    • 而且这个@Security注解似乎是保持可重用访问规则的好地方
    • 看来我无法理解您真正需要什么。如果你想将@Security 应用到整个控制器,你可以这样做。
    • 他想检查自定义类中其他控制器的权限。他想建立一个菜单而不是显示,例如,链接到菜单上的管理面板,如果管理员没有访问该链接的管理员权限。我想?
    • 问题是我在项目中有 4 个用户角色,并且其中还有很多控制器。目前所有的安全检查都是通过denyAccessUnlessGranted 方法执行的(通过自定义选民或简单的RoleHierarchyVoter)。因此,某些控制器只能用于特定角色。我还有一个菜单,其中包含指向该控制器的项目。我需要过滤当前用户无法访问的项目。这种过滤当然基于与控制器相同的安全检查。我只是不想在过滤期间再次复制此检查。
    猜你喜欢
    • 2016-05-18
    • 2012-03-03
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 2018-07-23
    • 2021-05-03
    • 1970-01-01
    • 2013-05-24
    相关资源
    最近更新 更多