如何在Symfony中将操作/方法(控制器)的访问限制为特定用户


How to restrict access of action/method (of Controller) to specific user in Symfony?

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

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

我已经研究了ACL及其完美,但我没有找到适合我的情况的解决方案,或者我在那里错过了一些东西。

寻求一些帮助和想法。

更新

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

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

SYMFONY>=2.6

  • 创建安全投票者
  • 如何使用投票者检查用户权限
  • 现在使用文档相应地更改访问决策策略

SYMFONY <=2.5

对于像这样的简单需求,您可以创建一个完全符合您需求的安全投票者(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!');
}

另请阅读如何使用选民检查用户权限

根据评论进行更新

也许知道要添加此行为的路由数会更好,但无论如何(如果您想避免在每个控制器中添加@AJCerqueti代码),您可以使用 Voter,如以下简单示例所示:

选民类:

// 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" />

现在,使用文档相应地更改访问决策策略。

这能满足您的需求吗?

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

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

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

您可以使用 Symfony2 的 AccessDeniedException

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

然后检查登录用户,

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

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抛出。

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