Symfony 2 - 从数据库加载角色

Mag*_*Hat 5 php security symfony

我的角色存储在数据库中,我试图在登录时动态加载它们.我正在做的是查询角色并将其设置在我的用户提供程序中的用户对象上,如下所示:

public function loadUserByUsername($username) {
    $q = $this
        ->createQueryBuilder('u')
        ->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();

        // Permissions
        $permissions = $this->_em->getRepository('E:ModulePermission')->getPermissionsForUser($user);

        if ($permissions !== null) {
            foreach ($permissions as $permission) {
                $name = strtoupper(str_replace(" ", "_", $permission['name']));

                $role = "ROLE_%s_%s";

                if ($permission['view']) {
                    $user->addRole(sprintf($role, $name, 'VIEW'));
                }

                if ($permission['add']) {
                    $user->addRole(sprintf($role, $name, 'ADD'));
                }

                if ($permission['edit']) {
                    $user->addRole(sprintf($role, $name, 'EDIT'));
                }

                if ($permission['delete']) {
                    $user->addRole(sprintf($role, $name, 'DELETE'));
                }
            }
        }

    } catch (NoResultException $e) {
        throw new UsernameNotFoundException(sprintf('Unable to find an active admin Entity:User object identified by "%s".', $username), null, 0, $e);
    }

    return $user;
}
Run Code Online (Sandbox Code Playgroud)

而用户实体:

class User implements AdvancedUserInterface, \Serializable {
    ....

    protected $roles;

    ....

    public function __construct() {
        $this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
        $this->roles = array();
    }


    ....


    public function getRoles() {
        $roles = $this->roles;

        // Ensure we having something
        $roles[] = static::ROLE_DEFAULT;

        return array_unique($roles);
    }

    public function addRole($role) {
        $role = strtoupper($role);
        $roles = $this->getRoles();
        if ($role === static::ROLE_DEFAULT) {
            return $this;
        }

        if (!in_array($role, $roles, true)) {
            $this->roles[] = $role;
        }

        return $this;
    }

    public function hasRole($role) {
        $role = strtoupper($role);
        $roles = $this->getRoles();
        return in_array($role, $roles, true);
    }
}
Run Code Online (Sandbox Code Playgroud)

这工作正常,花花公子,当我这样做时,我看到了正确的角色:

$this->get('security.context')->getUser()->getRoles()
Run Code Online (Sandbox Code Playgroud)

问题(我认为)是令牌不知道这些角色.因为在令牌上调用getRoles()只显示ROLE_USER,这是默认角色.

在我看来,令牌是在UserProvider加载用户之前创建的.我已经浏览了很多安全组件,但我不能在我的生活中找到正确的部分,以便正确设置这些角色,以便令牌知道它们.

更新从数据库文档加载角色后工作正常,但这与我的用例不匹配,如此处所示.我的架构不同,因为每个角色都有其他权限(查看/添加/编辑/删除),这就是我在这里尝试这种方法的原因.我不想改变我的架构只是为了使用Symfony的安全性.我宁愿理解为什么这些角色在我的用户对象上没有被正确绑定(不确定这里正确的学说词).

Seh*_*ael 8

看起来您可能不知道Symfony提供的内置角色管理.阅读文档 - 管理数据库中的角色 实际上很容易做到你想要的,你需要做的就是实现一个接口并定义你需要的功能.我链接的文档提供了很好的例子.看一看.

UPDATE

看起来文档没有为您use提供AdvancedUserInterface 的声明.这里是:

// in your user entity
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
Run Code Online (Sandbox Code Playgroud)

然后在你的角色实体中:

use Symfony\Component\Security\Core\Role\RoleInterface;
Run Code Online (Sandbox Code Playgroud)

文档向您展示如何完成剩下的工作.

UPDATE

看看这篇博文,其中展示了如何动态创建角色:

动态创建角色

  • 你的受保护的`roles`变量应该是`ArrayCollection`类型,所以在你的`getRoles`函数中,你重新定义了`$ roles`变量,所以它变成了一个新的数组,只有一个元素(你刚刚分配给它的ROLE_USER) ).[学说文档](http://www.doctrine-project.org/api/common/2.3/class-Doctrine.Common.Collections.ArrayCollection.html)向您展示了如何使用数组集合,您可能需要尝试`toArray()`函数,它将数组集转换为php数组. (2认同)

Mag*_*Hat 1

这里的问题源于我认为我正在实施

Symfony\Component\Security\Core\User\EquatableInterface;
Run Code Online (Sandbox Code Playgroud)

但不是(正如您在原始问题中看到的那样,我忘记将其添加到我的类定义中)。如果人们遇到它,我会把它留在这里。您所需要做的就是实现该接口,并将以下方法添加到您的用户实体中。

public function isEqualTo(UserInterface $user) {
    if ($user instanceof User) {
    // Check that the roles are the same, in any order
        $isEqual = count($this->getRoles()) == count($user->getRoles());
        if ($isEqual) {
            foreach($this->getRoles() as $role) {
                $isEqual = $isEqual && in_array($role, $user->getRoles());
            }
        }
        return $isEqual;
    }

    return false;
}
Run Code Online (Sandbox Code Playgroud)