Symfony2,路由和访问验证器

时间:2014-01-11 06:00:52

标签: php symfony routes

让我们想象一下,我们有用户和帖子。帖子链接在哪里

localhost/post/{postID}

如何检查sf2级别的安全性是此帖子的用户所有者(如果没有,则重定向)?我知道解决方案不多,但不想使用(我不想在此讨论原因)。

予。简单检查控制器。这个看似简单的检查(通过服务或正确的行动)。

if ($this->isOwner()){
return $this->redirect(...);
}

II。通过EventListener。这种情况更好,但并不好,因为我需要设置每个路由特定的规则。这个监听器每次都会执行,即使它有检查器(做或不检查)我不想要这个。

这个还有其他解决方案吗?

同样有趣的是如何检查'拥有编辑\删除现有帖子的用户权限'。

1 个答案:

答案 0 :(得分:1)

您可以创建PostAuthorizer,其任务是检查用户是否可以对帖子执行某些操作。为此,您可以注入AuthenticatedUserProvider直接在PostAuthorizer中获取经过身份验证的用户。

1 创建AuthenticatedUserProvider(我想你像所有人一样使用FOSUserBundle)。

<?php

namespace Acme\PostBundle\Security;

use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use FOS\UserBundle\Model\UserInterface;

/**
 * Provides the authenticated user
 */
class AuthenticatedUserProvider
{
    /**
     * The security context
     *
     * @var SecurityContextInterface
     */
    protected $securityContext;

    public function __construct(SecurityContextInterface $securityContext)
    {
        $this->securityContext = $securityContext;
    }

    /**
     * Gets the current authenticated user
     *
     * @return UserInterface
     */
    public function getAuthenticatedUser()
    {
        $user = $this->securityContext->getToken()->getUser();

        if (!$user instanceof UserInterface) {
            throw new AccessDeniedException('Must be logged in with a UserInterface instance');
        }

        return $user;
    }
}

2 并将其声明为服务:

services:
    #Authenticated User Provider
    acme_post.autenticated_user.provider:
        class: Acme\PostBundle\Security\AuthenticatedUserProvider
        arguments:
            securityContext: "@security.context"

3 创建PostAuthorizer

<?php

namespace Acme\PostBundle\Security;

use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Acme\PostBundle\Entity\PostInterface;
use Acme\PostBundle\Security\AuthenticatedUserProvider;

/**
 * Manages permissions to manipulate posts
 */
class PostAuthorizer
{
    /**
     * The user provider
     *
     * @var AuthenticatedUserProvider
     */
    protected $authenticatedUserProvider;

    public function __construct(AuthenticatedUserProvider $authenticatedUserProvider)
    {
        $this->authenticatedUserProvider = $authenticatedUserProvider;
    }

    /**
     * Tells if the current user is allowed
     * to see this post
     *
     * @param PostInterface $post
     * @return boolean
     */
    public function canSeePost(PostInterface $post)
    {
        return ($this->getAuthenticatedUser()->getId()  === $post->getOwner()->getId());
    }

    /**
     * Tells if the current participant is allowed
     * to delete this post
     *
     * @param PostInterface $post
     * @return boolean
     */
    public function canDeletePost(PostInterface $post)
    {
        return $this->canSeePost($post);
    }

    /**
     * Tells if the current participant is allowed
     * to edit this post
     *
     * @param PostInterface $post
     * @return boolean
     */
    public function canEditPost(PostInterface $post)
    {
       return $this->canSeePost($post);
    }

    /**
     * Gets the current authenticated user
     *
     * @return FOS\UserBundle\Model\UserInterface
     */

    protected function getAuthenticatedUser()
    {
        return $this->authenticatedUserProvider->getAuthenticatedUser();
    }
}

4 并将其声明为服务

services:
    acme_post.post.authorizer:
        class: Acme\PostBundle\Security\PostAuthorizer
        arguments:
            authenticatedUserProvider: "@acme_post.autenticated_user.provider"

5 最后,在您的控制器中(如果需要,可以在帖子提供者中),您可以这样做:

if( !$this->container->get('acme_post.post.authorizer')->canSeePost($post) ) {
    throw new AccessDeniedException('You are not allowed to see this post');
}

// can safely display the post now