Symfony2 - 添加控制器安全性以限制用户对特定博客的访问

Posted

技术标签:

【中文标题】Symfony2 - 添加控制器安全性以限制用户对特定博客的访问【英文标题】:Symfony2 - Adding controller security to limit the user to a specific blog access 【发布时间】:2014-09-27 15:13:30 【问题描述】:

我正在尝试通过对每个用户使用 USER_ROLE 来实施安全性以限制对特定博客的访问。每个博客页面都有 1 位可以向其发帖的所有者。

这是基于我从 KNP 大学的精彩教程中学到的。

http://knpuniversity.com/screencast/symfony2-ep2

我已经使用 security.yml 中的 access_control 进行了设置,以根据每个用户的 USER_ROLE 限制对每个用户的访问。 (user1 可以访问 /job1/new 和 /job1/create 以便在博客页面上创建/编辑/删除帖子——每个博客页面只有 1 个用户可以访问)

access_control:
    -  path: ^/job1/new, roles: [ROLE_USER1, ROLE_ADMIN] 
    -  path: ^/job2/new, roles: [ROLE_USER2, ROLE_ADMIN] 
    -  path: ^/job3/new, roles: [ROLE_USER3, ROLE_ADMIN] 
    -  path: ^/job1/create, roles: [ROLE_USER1, ROLE_ADMIN] 
    -  path: ^/job2/create, roles: [ROLE_USER2, ROLE_ADMIN] 
    -  path: ^/job3/create, roles: [ROLE_USER3, ROLE_ADMIN] 

每个 /job1、/job2 等都是独立的博客页面。我在 Twig 中使用 if 语句来确定哪个用户有权创建/编辑/删除帖子。

% if is_granted('ROLE_USER1') %
    <li><a href=" path('job1_new') ">Add New Post</a></li>
% endif %

问题是,当我添加更多博客页面时,我需要在访问控制中创建更多路径(例如,/job4、/job5 等),尽管它确实有效,但这并不是一个理想的解决方案。

我在下面的链接中详细介绍了代码,因为建议在控制器中使用基于与 Ryan Weaver 的 Disqus 对话“joe joe”的安全性 ---http://knpuniversity.com/screencast/symfony2-ep2

我的问题是:

1) 现在我已经与 User 和 Category 创建了 ManyToMany 关系,如何在控制器中设置安全性以防止其他用户访问他们没有角色的创建/编辑/删除操作?

2) 如何在 Twig 中隐藏选项以使用此方法创建/编辑/删除/以及使用此方法在 access_control 中添加什么?

【问题讨论】:

【参考方案1】:

我认为您应该使用 Security Bundle 中的内置 Voter。因此,您创建一个与用户实体 1:1 关系的博客实体,然后 create a Voter service,在 vote 方法中构建您的逻辑,在控制器中使用该选民,就是这样。这是示例:

class SomeVoter implements VoterInterface

    const CREATE = 'create';
    const EDIT = 'edit';
    const DELETE = 'delete';

    /**
     * @param string $attribute
     * @return bool
     */
    public function supportsAttribute($attribute)
    
        return in_array($attribute, array(
            self::CREATE,
            self::EDIT,
            self::DELETE
        ));
    

    /**
     * @param string $class
     * @return bool
     */
    public function supportsClass($class)
    
        $supportedClass = 'Acme\DemoBundle\Entity\Blog';

        return $supportedClass === $class || is_subclass_of($class, $supportedClass);
    

    /**
     * @param TokenInterface $token
     * @param object $blog
     * @param array $attributes
     * @return int
     */
    public function vote(TokenInterface $token, $blog, array $attributes)
    
        ....

        $attribute = $attributes[0];
        $user = $token->getUser();

        switch($attribute) 
            case 'edit':
                if ($user->getId() === $blog->getUser()->getId()) 
                    return VoterInterface::ACCESS_GRANTED;
                
                break;

            ....
        

        ...
    

控制器动作:

public function editAction($id)

    $blog = ...;

    if (false === $this->get('security.context')->isGranted('edit', $blog)) 
        throw new AccessDeniedException('Unauthorised access!');
    

    ...

【讨论】:

【参考方案2】:

增加访问控制以使其需要明确包含每个新用户是不现实的。相反,可以使用 ROLE_USER 只允许经过身份验证的用户访问编辑/创建任何实体(例如,博客)。一旦用户通过身份验证,控制器就可以提供对该用户博客实体的访问。

这需要用户和博客之间的一对多关系。在控制器中,它就变成了这样一个简单的事情:

...
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;

/**
 * ...
 * @Security("has_role('ROLE_USER')")
 */

class BlogifyController extends Controller


   public function blogAction
    
        $user = $this->getUser();
        $blogs = $user->getBlogs();
    // do your form thing, etc.
    ...
    

【讨论】:

以上是关于Symfony2 - 添加控制器安全性以限制用户对特定博客的访问的主要内容,如果未能解决你的问题,请参考以下文章

为啥要修改nginx用户和组

Symfony2:使用 FOSUserBundle 时如何在控制器内获取用户对象?

Symfony2 限制最终用户仅上传 csv 文件

CentOS 7 中httpd服务的用户限制详解

数据安全小结

Apache的访问控制