【问题标题】:How to restrict access of action/method (of Controller) to specific user in Symfony?如何限制对 Symfony 中特定用户的操作/方法(控制器)的访问?
【发布时间】:2023-04-07 16:15:01
【问题描述】:

有没有办法根据用户限制对特定路由的访问,也就是 Symfony 中控制器的操作/方法?

我正在为用户管理实现 FOSUserBundle,如果我有具有已定义角色的用户,它具有定义权限的角色,但如果我想根据用户限制页面,我必须为每个路由创建角色,或者是否有任何更好的方法。

我已经研究了 ACL 及其完美,但我没有找到适合我的情况的解决方案,或者我在那里遗漏了什么。

寻求一些帮助和想法。

更新

@AJ Cerqueti - 答案可以快速解决,但如果有的话,我正在寻找更好的方法。

更具体地说,是否可以使用 ACL 或其他更好的方法为用户分配路由的访问权限。

【问题讨论】:

    标签: php symfony acl fosuserbundle


    【解决方案1】:

    SYMFONY >=2.6

    SYMFONY

    对于这样的简单需求,您可以create a security voter 完全符合您的需求(ACL 通常用于复杂需求,也因为不容易实现)。

    然后您可以在控制器中使用投票器,如文档中所述:

    // get a Post instance
    $post = ...;
    
    // keep in mind, this will call all registered security voters
    if (false === $this->get('security.authorization_checker')->isGranted('view', $post)) {
        throw new AccessDeniedException('Unauthorised access!');
    }
    

    另请阅读How to Use Voters to Check User Permissions

    根据评论更新

    也许会更好地了解您想要添加此行为的路线数量,但无论如何(如果您想避免在每个控制器中添加@AJCerqueti 代码)您可以使用像这个简单示例中的投票者:

    选民类别:

    // src/AppBundle/Security/Authorization/Voter/RouteVoter.php
    namespace AppBundle\Security\Authorization\Voter;
    
    use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;    
    
    class RouteVoter implements VoterInterface
    {
        private   $routes;
    
        public function __construct(array $routes = array())
        {
            $this->routes        = $routes;
        }
    
        public function supportsAttribute($attribute)
        {
            // you won't check against a user attribute, so return true
            return true;
        }
    
        public function supportsClass($class)
        {
            // your voter supports all type of token classes, so return true
            return true;
        }
    
        public function vote(TokenInterface $token, $object, array $attributes)
        {
            // get get allowed routes from current logged in user 
            $userRoutes = $token->getUser()->getRoutes();
    
            // implement as you want the checks and return the related voter constant as below
    
            if (...) {# your implementation
    
                return VoterInterface::ACCESS_DENIED;    
            }
    
            return VoterInterface::ACCESS_ABSTAIN;
        }
    }
    

    登记选民:

    <service id="security.access.route_voter"
         class="AppBundle\Security\Authorization\Voter\RouteVoter" public="false">
    <argument type="collection">
        <argument>route_one</argument>
        <argument>route_two</argument>
    </argument>
    <tag name="security.voter" />
    

    Now change the access decision strategy accordingly with the docs.

    这能满足你的需要吗?

    【讨论】:

    • 感谢您的回答,但到目前为止,我知道选民是特定于对象的,我使用 ACL 感觉很好,但只支持对象范围或类范围。在这里,我正在寻找一种方法,是否可以使用 ACL 或其他最佳方法为路由上的用户分配访问权限。
    • 谢谢@gp_sflover。稍后会检查,我可以动态地实现这一点(只需使用 UI)。
    • 感谢您的想法,我已经创建了一个路由实体并将用户分配给实体。如果我要结束,我将分享路线的多个角色的结果用户。在那之前,我会投票给@gp_sflover 答案。
    • @gp_sflover $token-&gt;getUser()-&gt;getRoutes(); 来自哪里?我的意思是这些路线在哪里以及如何存储?它只是用户表中的一列还是什么?
    • @bought777 是的,$token-&gt;getUser()-&gt;getRoutes(); 指的是用户表的一列。只是一个关于如何检索该登录用户的允许路由的简单示例。
    【解决方案2】:

    同意以前的答案,即 ACL、选民或某种基于角色的解决方案绝对是最佳实践方法,但对于这种边缘情况,建议扩展您的 FOSUser 以添加“slug”字段,然后检查:

    if('accessible_slug' !== $this->get('security.context')->getToken()->getUser()->getSlug()) {
    throw new AccessDeniedException()
    }
    

    这意味着为一组控制器/动作设置一个 slug,并将它们设置给用户。类似于角色,但没有那么多开销。仍然更喜欢 Voters 和某种角色层次结构,但希望这会有所帮助。

    【讨论】:

    • 这可能是快速修复,但我正在等待是否有更好的方法。
    • 如前所述,最好的方法可能是基于分层角色的。我为您创建了一个小要点,向您展示如何在 Symfony 中创建分层角色系统:gist.github.com/ajcerqueti/a5dc10b21971493b3935
    【解决方案3】:

    你可以使用 Symfony2 的 AccessDeniedException

    use Symfony\Component\Security\Core\Exception\AccessDeniedException;
    

    然后检查登录用户,

    if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) {
                throw new AccessDeniedException();
            } else {
    Continue;
        }
    

    【讨论】:

    • 澄清一下,对于控制器 CRUD 操作,如果所有用户都有 ROLE_ADMIN 但我想只允许特定用户执行创建操作并阻止其他用户。同样,允许基于用户分配读取、更新、创建、删除。
    • 那么,如果所有用户都有角色 ROLE_ADMIN 你将如何区分两个用户?
    • 这就是我想要的! (可能与否?)因此,我得出了一个结论,即为每个操作/方法(路由)定义角色并将角色分配给用户,这既乏味又不是一个好方法。除了这种方法还有其他方法吗。我说清楚了吗?
    【解决方案4】:

    app/config/security.yml 中有一个部分access_control:。您可以在那里定义特定路径的访问限制,例如。 - { path: ^/faq/admin, roles: ROLE_FAQ_ADMIN }

    path 参数是一个正则表达式,因此上述条目将限制对以/faq/admin 开头的任何路径的访问,例如。 /faq/admin/show-something/faq/admin/show-something-else 等。只有具有指定角色的用户才能访问这些路径。对于其他用户,AccessDeniedException 将被抛出 HTTP 代码 403。

    无需更改控制器内操作中的代码。

    【讨论】:

      猜你喜欢
      • 2023-03-14
      • 2013-12-08
      • 2015-10-12
      • 1970-01-01
      • 2016-05-27
      • 2020-02-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多