Symfony 2 - Loading roles from database

陌路散爱 提交于 2021-02-17 20:51:36

问题


My roles are stored in the database and I am trying to load them dynamically upon login. What I'm doing is querying for the roles and setting them on the user object in my user provider as seen here:

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

And the user entity:

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 works fine and dandy and I see the correct roles when I do:

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

The problem (I think), is that the token does not know about these roles. Because calling getRoles() on the token is showing only ROLE_USER, which is the default role.

It seems to me that the token is being created before the user is loaded by the UserProvider. I've looked through a lot of the security component but I can't for the life of me find the right part of the process to hook into to set these roles correctly so that the token knows about them.

Update Following the Load roles from database doc works fine, but this does not match my use case as shown here. My schema differs as each role has additional permissions (view/add/edit/delete) and this is why I am attempting the approach here. I don't want to have to alter my schema just to work with Symfony's security. I'd rather understand why these roles are not properly bound (not sure the correct doctrine word here) on my user object at this point.


回答1:


It looks like you may not be aware of the built in role management that Symfony offers. Read the docs - Managing roles in the database It is actually quite simple to do what you want, all you need to do is implement an interface and define your necessary function. The docs I linked to provide great examples. Take a look.

UPDATE

It looks like the docs don't give you the use statement for the AdvancedUserInterface. Here it is:

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

then in your role entity:

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

The docs show you how to do the rest.

UPDATE

Take a look at this blog post, which shows how to create roles dynamically:

Dynamically create roles




回答2:


The problem here stemmed from the fact that I thought I was implementing

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

but wasn't (as you can see in the original question, I forgot to add it to my class definition). I'm leaving this here for people if they come across it. All you need is to implement this interface, and add the following method to your user entity.

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


来源:https://stackoverflow.com/questions/21005680/symfony-2-loading-roles-from-database

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!