Symfony 2 ACL和角色层次结构

时间:2022-09-12 11:25:22

I'm a little stuck and unable to find the answer to this.

我有点陷入困境,无法找到答案。

In my app test I've created two Entities User and Comment both are mapped correctly.

在我的应用测试中,我创建了两个实体用户和注释都正确映射。

I have created a small controller which depending on the user will add the comment and the data to the ACL tables, if I create my comment as a standard user with the associated for of 'ROLE_USER', and Try to access it as user with the role 'ROLE_ADMIN' I get access denied, it seems to completely ignore the security.yml hierarchy.

我创建了一个小控制器,根据用户将注释和数据添加到ACL表,如果我创建我的注释作为标准用户与“ROLE_USER”关联,并尝试以用户身份访问它角色'ROLE_ADMIN'我被拒绝访问,似乎完全忽略了security.yml层次结构。

I know this works by adding instead of the userid the ROLE_USER etc but I don't want to do it this way.

我知道这可以通过添加而不是用户ID ROLE_USER等来工作,但我不想这样做。

Examples of my code are below.

我的代码示例如下。

CommentController

CommentController

    <?php

    namespace ACL\TestBundle\Controller;

    use Symfony\Bundle\FrameworkBundle\Controller\Controller;
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
    use Symfony\Component\HttpFoundation\Request;
    use ACL\TestBundle\Forms\Type\commentType;
    use ACL\TestBundle\Entity\Comment;
    use Symfony\Component\Security\Core\Exception\AccessDeniedException;
    use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
    use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
    use Symfony\Component\Security\Acl\Permission\MaskBuilder;

    class DefaultController extends Controller
    {
        /**
         * @Route("/", name="_default")
         * @Template()
         */
        public function indexAction()
        {
            die('success');
        }

        /**
         * @Route("/comment/new/")
         * @Template()
         */
        public function newAction(Request $request)
        {
            $comment = new Comment();

            $form = $this->createForm(new commentType(), $comment);

            $form->handleRequest($request);

            if ($form->isValid()) {
                $comment->setUsers($this->getUser());
                $em = $this->getDoctrine()->getManager();
                $em->persist($comment);
                $em->flush();

                // creating the ACL
                $aclProvider = $this->get('security.acl.provider');
                $objectIdentity = ObjectIdentity::fromDomainObject($comment);
                $acl = $aclProvider->createAcl($objectIdentity);

                // retrieving the security identity of the currently logged-in user
                $securityIdentity = UserSecurityIdentity::fromAccount($this->getUser());

                // grant owner access
                $acl->insertObjectAce($securityIdentity, MaskBuilder::MASK_OWNER);
                $aclProvider->updateAcl($acl);
            }

            return array(
                'form' => $form->createView(),
            );
        }

        /**
         * @Route("/comment/{id}/", requirements={"id":"\d+"})
         * @Template()
         */
        public function editAction(Request $request,$id)
        {
            $em = $this->getDoctrine()->getManager();
            $comment = $em->find('ACLTestBundle:Comment', $id);

            $securityContext = $this->get('security.context');

            // check for edit access
            if (false === $securityContext->isGranted('EDIT',$comment)) {
                throw new AccessDeniedException();
            }

            $form = $this->createForm(new commentType(), $comment);

            $form->handleRequest($request);

            if($form->isValid()){
                $em->persist($comment);
                $em->flush();
            }

            return array('form' => $form->createView());
        }
    }

security.yml

security.yml

 security:
        encoders:
            ACL\TestBundle\Entity\User: plaintext
        acl:
            connection: default

        providers:
            database:
                entity: { class: ACLTestBundle:User }

        role_hierarchy:
            ROLE_ADMIN: [ROLE_USER, ROLE_ALLOWED_TO_SWITCH]

        firewalls:
            dev:
                pattern:  ^/(_(profiler|wdt)|css|images|js)/
                security: false
            main:
                pattern:     ^/
                provider:    database
                anonymous:   true
                logout:      true
                switch_user: true
                form_login:
                    login_path: _security_login

        access_control:
            - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
            - { path: ^/, roles: IS_AUTHENTICATED_FULLY }

I appreciate any advice!

我很感激任何建议!

1 个解决方案

#1


5  

The problem is that you are adding adding ACL base on UserIdentity and want to check the gran base on RoleIdentity. If you want to do it Role base change the creating ACL as below

问题是您正在添加基于UserIdentity的ACL并希望检查基于RoleIdentity的gran。如果要这样做,角色库将更改创建ACL,如下所示

// creating the ACL
$aclProvider = $this->get('security.acl.provider');
$objectIdentity = ObjectIdentity::fromDomainObject($comment);
$acl = $aclProvider->createAcl($objectIdentity);

// retrieving the security identity of the currently logged-in user
$securityIdentity = UserSecurityIdentity::fromAccount($this->getUser());

// grant owner access
$acl->insertObjectAce($securityIdentity, MaskBuilder::MASK_OWNER);

// grant EDIT access to ROLE_ADMIN
$securityIdentity = new RoleSecurityIdentity('ROLE_ADMIN');
$acl->insertObjectAce($securityIdentity, MaskBuilder::MASK_EDIT);
$aclProvider->updateAcl($acl);

As you see I kept the owner access for the specific user then I added Edit access for ROLE_ADMIN. You can keep the controller as is.

如您所见,我保留了特定用户的所有者访问权限,然后我添加了ROLE_ADMIN的编辑权限。您可以保持控制器不变。

If you don't want to make it Role base but just want to give an exception for admin users you can change your controller as

如果您不想将其作为角色基础但只想为管理员用户提供例外,则可以将控制器更改为

// check for edit access
if (false === $securityContext->isGranted('EDIT',$comment) && false === $securityContext->isGranted('ROLE_ADMIN') ) {
   throw new AccessDeniedException();
}

#1


5  

The problem is that you are adding adding ACL base on UserIdentity and want to check the gran base on RoleIdentity. If you want to do it Role base change the creating ACL as below

问题是您正在添加基于UserIdentity的ACL并希望检查基于RoleIdentity的gran。如果要这样做,角色库将更改创建ACL,如下所示

// creating the ACL
$aclProvider = $this->get('security.acl.provider');
$objectIdentity = ObjectIdentity::fromDomainObject($comment);
$acl = $aclProvider->createAcl($objectIdentity);

// retrieving the security identity of the currently logged-in user
$securityIdentity = UserSecurityIdentity::fromAccount($this->getUser());

// grant owner access
$acl->insertObjectAce($securityIdentity, MaskBuilder::MASK_OWNER);

// grant EDIT access to ROLE_ADMIN
$securityIdentity = new RoleSecurityIdentity('ROLE_ADMIN');
$acl->insertObjectAce($securityIdentity, MaskBuilder::MASK_EDIT);
$aclProvider->updateAcl($acl);

As you see I kept the owner access for the specific user then I added Edit access for ROLE_ADMIN. You can keep the controller as is.

如您所见,我保留了特定用户的所有者访问权限,然后我添加了ROLE_ADMIN的编辑权限。您可以保持控制器不变。

If you don't want to make it Role base but just want to give an exception for admin users you can change your controller as

如果您不想将其作为角色基础但只想为管理员用户提供例外,则可以将控制器更改为

// check for edit access
if (false === $securityContext->isGranted('EDIT',$comment) && false === $securityContext->isGranted('ROLE_ADMIN') ) {
   throw new AccessDeniedException();
}