Symfony 2 - 从数据库加载角色

时间:2014-01-08 20:20:38

标签: 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;
}

用户实体:

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);
    }
}

这样做很好,花花公子,我看到了正确的角色:

$this->get('security.context')->getUser()->getRoles()

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

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

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

2 个答案:

答案 0 :(得分:8)

看起来您可能不知道Symfony提供的内置角色管理。阅读文档 - Managing roles in the database实际上很容易做你想做的事情,你需要做的就是实现一个接口并定义你需要的功能。我链接的文档提供了很好的例子。看一看。

更新

看起来文档没有为AdvancedUserInterface提供use语句。这是:

// in your user entity
use Symfony\Component\Security\Core\User\AdvancedUserInterface;

然后在您的角色实体中:

use Symfony\Component\Security\Core\Role\RoleInterface;

文档向您展示如何完成其​​余工作。

更新

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

Dynamically create roles

答案 1 :(得分:1)

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

Symfony\Component\Security\Core\User\EquatableInterface;

但不是(正如你在原始问题中看到的那样,我忘了把它添加到我的班级定义中)。如果遇到它,我会把它留给人们。您只需要实现此接口,并将以下方法添加到您的用户实体。

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;
}