1

我有实体用户(实现 UserInterface,它与实体角色有多对多关系(实现 RoleInterface)。

我的项目在登录后需要 ROLE_ADMIN,否则会返回 AccessDenied 错误。此外,我在我的数据库的 Role 表中添加了一个 ROLE_ADMIN 角色,并在我的 user_Roles(多对多)表中创建了一个与此角色相关的用户。

但是当我登录时,我总是得到 AccessDenied 错误。

当我将 User 中的 getRoles() 方法更改为return array('ROLE_ADMIN');有效时。

有任何想法吗?

另外我必须在用户中添加此方法,否则我无法在我的数据库中添加用户。

  public function setUserRoles($userRoles)
    {
        if ( is_array($userRoles) ) {
            $this->userRoles = $userRoles ;
        } else {
            $this->userRoles->clear() ;
            $this->userRoles->add($userRoles) ;
        }
        return $this;
    }

用户:

namespace Acme\AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\EquatableInterface;
/**
 * User
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class User implements UserInterface, \Serializable
{   



    /**
     * @ORM\ManyToMany(targetEntity="Role", inversedBy="users")
     * @ORM\JoinTable(name="user_roles")
     *
     */
    private $userRoles;


    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(type="string", length=35, unique=true)
     */
    private $username;


    /**
     * @ORM\Column(type="string", length=32)
     */
    private $salt;

    /**
     * @ORM\Column(type="string", length=100)
     */
    private $password;

    /**
     * @ORM\Column(type="string", length=60)
     */
    private $name;

    /**
     * @ORM\Column(name="is_active", type="boolean")
     */
    private $isActive;

    public function __construct()
    {
        $this->isActive = true;
        $this->salt = md5(uniqid(null, true));
        $this->userRoles = new ArrayCollection();
    }

    /*
     * --Interface Methoden--
     */
    /**
     * @inheritDoc
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * @inheritDoc
     */
    public function getSalt()
    {
        return $this->salt;
    }

    /**
     * @inheritDoc
     */
    public function getPassword()
    {
        return $this->password;
    }

    /**
     * @inheritDoc
     */
    public function getRoles()
    {
        return $this->userRoles->toArray();

    }

    /**
     * @inheritDoc
     */
    public function eraseCredentials()
    {
    }

    /**
     * @see \Serializable::serialize()
     */
    public function serialize()
    {
        return serialize(array(
                $this->id,
        ));
    }

    /**
     * @see \Serializable::unserialize()
     */
    public function unserialize($serialized)
    {
        list (
                $this->id,
        ) = unserialize($serialized);
    }






    public function isEqualTo(UserInterface $user)
    {
        return $this->id === $user->getId();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set username
     *
     * @param string $username
     * @return User
     */
    public function setUsername($username)
    {
        $this->username = $username;

        return $this;
    }

    /**
     * Set salt
     *
     * @param string $salt
     * @return User
     */
    public function setSalt($salt)
    {
        $this->salt = $salt;

        return $this;
    }

    /**
     * Set password
     *
     * @param string $password
     * @return User
     */
    public function setPassword($password)
    {
        $this->password = $password;

        return $this;
    }



    /**
     * Set isActive
     *
     * @param boolean $isActive
     * @return User
     */
    public function setIsActive($isActive)
    {
        $this->isActive = $isActive;

        return $this;
    }

    /**
     * Get isActive
     *
     * @return boolean 
     */
    public function getIsActive()
    {
        return $this->isActive;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return User
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }



    public function setUserRoles($userRoles)
    {
        if ( is_array($userRoles) ) {
            $this->userRoles = $userRoles ;
        } else {
            $this->userRoles->clear() ;
            $this->userRoles->add($userRoles) ;
        }
        return $this;
    }

    /**
     * Add userRoles
     *
     * @param \Amce\AppBundle\Entity\Role $userRoles
     * @return User
     */
    public function addUserRole(\Acme\AppBundle\Entity\Role $userRoles)
    {
        $this->userRoles[] = $userRoles;

        return $this;
    }

    /**
     * Remove userRoles
     *
     * @param \Acme\AppBundle\Entity\Role $userRoles
     */
    public function removeUserRole(\Acme\AppBundle\Entity\Role $userRoles)
    {
        $this->userRoles->removeElement($userRoles);
    }

    /**
     * Get userRoles
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getUserRoles()
    {
        return $this->userRoles;
    }
}

角色:

namespace Acme\AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Security\Core\Role\RoleInterface;
use Doctrine\ORM\Mapping as ORM;

/**
 * Role
 *
 * @ORM\Table()
 * @ORM\Entity
 */
class Role implements RoleInterface
{

    /**
     * @ORM\ManyToMany(targetEntity="User", mappedBy="userRoles")
     *
     */
    private $users;

    public function __construct()
    {
        $this->users = new ArrayCollection();
    }

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     */
    private $name;


    /*
     * methods for RoleInterface
    */
    public function getRole()
    {
        $this->getName();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Role
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Add users
     *
     * @param \Acme\AppBundle\Entity\User $users
     * @return Role
     */
    public function addUser(\Acme\AppBundle\Entity\User $users)
    {
        $this->users[] = $users;

        return $this;
    }

    /**
     * Remove users
     *
     * @param \Acme\AppBundle\Entity\User $users
     */
    public function removeUser(\Acme\AppBundle\Entity\User $users)
    {
        $this->users->removeElement($users);
    }

    /**
     * Get users
     *
     * @return \Doctrine\Common\Collections\Collection 
     */
    public function getUsers()
    {
        return $this->users;
    }
}

安全.yml

    jms_security_extra:
    secure_all_services: false
    expressions: true

security:
    encoders:
        Acme\AppBundle\Entity\User: sha512
        Symfony\Component\Security\Core\User\User: plaintext


    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    providers:
        chain_providers:
            chain:
                providers: [main, in_memory]
        main:
            entity: { class: Acme\AppBundle\Entity\User, property: username }
        in_memory:
            memory:
                users:
                    user:  { password: userpass, roles: [ 'ROLE_USER' ] }
                    admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] }

    firewalls:

        secured_area:
            pattern:    .*
            form_login: ~
            logout: ~
            anonymous: ~
            #http_basic:
            #    realm: "Secured Demo Area"

    #access_control:
        #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }

用户存储库:

namespace Acme\AppBundle\Entity;

use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\NoResultException;

class UserRepository extends EntityRepository implements UserProviderInterface
{
    public function loadUserByUsername($username)
    {
        $q = $this
            ->createQueryBuilder('u')
            ->select('u, r')
            ->leftJoin('u.userRoles', 'r')
            ->where('u.username = :username')
            ->setParameter('username', $username)
            ->getQuery();


        try {
            // The Query::getSingleResult() method throws an exception
            // if there is no record matching the criteria.
            $user = $q->getSingleResult();
        } catch (NoResultException $e) {
            $message = sprintf(
                'Unable to find an active admin AcmeUserBundle:User object identified by "%s".',
                $username
            );
            throw new UsernameNotFoundException($message, 0, $e);
        }

        return $user;
    }
...
}

测试:

public function testLoadUserByUsername()
{
    $users = $this->em
    ->getRepository('AcmeAppBundle:User')
    ->loadUserByUsername('admintest')
    ;
    $test = $users->getRoles();

    print $test[0];
    $this->assertCount(1, $users);
}
4

1 回答 1

4

请确保您在UserRepository中的loadUserByUsername()在您的User实体上正确加入相应的角色,并且 User->getRoles() (和 Role->getRole() 在您的角色实体上)返回正确的数组/字符串。

您可以在 TestController 中进行测试,例如通过手动查询 UserRepository::loadUserByUsername() 方法并检查角色是否存在。

下一个可能性是延迟加载问题。尝试:

/**
 * @ORM\ManyToMany(targetEntity="Role", inversedBy="users", fetch="EAGER")
 * @ORM\JoinTable(name="user_roles")
 *
 */
private $userRoles;

文档说:

在从自定义实体提供程序检索用户时提高性能并避免延迟加载组。

如果这不是您的问题的解决方案,请发表评论,无论如何,通过急切加载获取用户组或用户角色关系是一个好习惯。

请记住在更改获取设置后清除缓存!

小费:

关于您的 addRole 方法......您很可能不想多次向您的用户添加角色实体,但前提是它们尚未添加。最好这样写:

public function addRole(RoleInterface $role)
{
   if (!$this->roles->contains($role)) {
       $this->roles->add($role);
   }

    return $this;
}
于 2013-05-25T17:39:12.657 回答