问题
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.
I know this works by adding instead of the userid the ROLE_USER etc but I don't want to do it this way.
Examples of my code are below.
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:
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:
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
// 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.
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();
}
来源:https://stackoverflow.com/questions/23406203/symfony-2-acl-and-role-hierarchy