验证用户是否可以执行操作

时间:2017-01-05 15:15:32

标签: php symfony

我有两个人和托儿所以及他们之间的ManyToMany关联。

用户可以拥有角色ROLE_MANAGER并成为多个托儿所的经理。

对于他的仪表板上的每一个动作,我需要验证他是否与托儿所相关联,如果我不这样做,他可以修改网址中的苗圃slu and并且可以访问他没有链接的托儿所。

有没有办法检查托儿所经理仪表板中的每个操作,而无需在每个操作中复制/粘贴验证码?

据我所知,Symfony Events(或Voters?)可以做到这一点,但我以前从未使用它们......

编辑:也许用一点代码更容易理解! 所以我的托儿所仪表板功能是:

public function dashboardAction($nursery_slug)
{
    //$currentUser = $this->get('security.token_storage')->getToken()->getUser();
    $nurseryRepo = $this->getDoctrine()->getRepository('VSCrmBundle:Nursery');

    $nursery = $nurseryRepo->findOneBy(array('slug' => $nursery_slug));

    // Sometimes may help
    if(!$nursery)
    {
        throw $this->createNotFoundException("The nursery has not been found or you are not allowed to access it.");
    }

    return $this->render("VSCrmBundle:Manager:dashboard.html.twig", array(
        'nursery' => $nursery
    ));
}

为了保护这个仪表板,我需要验证当前用户是否链接到托儿所,有些想法:

$verification = $nurseryRepo->findOneBy(array('person' => $currentUser));
if(!$verification){throw accessDeniedException();}

但目前我不得不对经理仪表板中的每一个动作进行测试......

1 个答案:

答案 0 :(得分:1)

要使这项工作顺利进行,您需要执行两项操作。

首先,你需要一个NurseryVoter:http://symfony.com/doc/current/security/voters.html

类似的东西:

class NurseryVoter extends Voter
{
    const MANAGE = 'manage';

    protected function supports($attribute, $subject)
    {
        if (!in_array($attribute, array(self::MANAGE))) {
            return false;
        }
        if (!$subject instanceof Nursery) {
            return false;
        }
        return true;
    }
    protected function voteOnAttribute($attribute, $nursery, TokenInterface $token)
    {
        $user = $token->getUser();

        if (!$user instanceof User) {
            // the user must be logged in; if not, deny access
            return false;
        }
        // Check the role and do your query to verify user can manage specific nursery

根据链接连接所有内容。此时,您的控制器代码将减少为:

$this->denyAccessUnlessGranted('manage', $nursery);

让所有工作先行。之后,使用Kernel:Controller事件将拒绝访问代码从控制器移动到侦听器。按照文档:http://symfony.com/doc/current/event_dispatcher.html

在分配控制器之后但在实际调用控制器操作之前调用控制器侦听器。这里的技巧是如何确定哪个动作实际需要进行检查。有几种方法。有些人喜欢通过添加NurseryManagerInterface来标记实际的控制器类。侦听器检查控制器以查看它是否具有接口。但我真的不在乎。

我喜欢将这种东西直接添加到路线中。所以我可能会:

// routes.yml
manage_nursery:
    path: /manage/{nursery}
    defaults:
        _controller: manage_nursery_action
        _permission: CAN_MANAGE_NURSERY

然后,您的听众将检查权限。

更新了有关内核侦听器的更多详细信息。基本上,您注入授权检查器并从请求对象中拉出_permission。

class KernelListener implements EventSubscriberInterface
{
    // @security.authorization_checker service
    private $authorizationChecker;

    public function __construct($authorizationChecker,$nuseryRepository)
    {
        $this->authorizationChecker = $authorizationChecker;
        $this->nurseryRepository = $nuseryRepository;
    }
    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::CONTROLLER => [['onController']],
        ];
    }
    public function onController(FilterControllerEvent $event)
    {
        $request = $event->getRequest();
        $permission = $request->attributes->get('_permission');
        if ($permission !== 'CAN_MANAGE_NURSERY') {
            return;
        }
        $nursery = $this->nurseryRepository->find($request->attributes->get('nursery');

        if ($this->authorizationChecker->isGranted('MANAGE',$nursery) {
            return;
        }
        throw new AccessDeniedException('Some message');
    }