如何限制 action/method(控制器)对 Symfony 中特定用户的访问?

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

有没有办法根据用户限制对 Symfony 中控制器的特定路由又名 action/method 的访问?

我正在实施 FOSUserBundle 进行用户管理,它具有用于定义权限的角色,如果我的用户具有已定义的角色,则效果很好,但如果我想根据用户限制页面,我必须为每条路线创建角色,或者是还有更好的办法吗

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

寻求一些帮助和想法。

更新

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

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

你可以使用 Symfony2

A​​ccessDeniedException
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

然后检查登录用户,

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

SYMFONY >=2.6

SYMFONY <=2.5

对于像这样的简单需求,您可以 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 代码)您可以使用像这样的投票器简单示例:

选民Class:

// 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、选民或某种基于角色的解决方案绝对是最佳实践方法,但对于这种边缘情况,建议扩展您的 FOSUser 以添加 'slug' 字段,并且然后检查一下:

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

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

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。

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