A
A
Anton2017-04-07 14:34:53
symfony
Anton, 2017-04-07 14:34:53

How to competently organize the loading of roles from the database in Symfony3?

I'm almost there.
There is a User table, a Role table, a user_role table for linking many-to-many users and roles.
The user model provides a getRoles() method and

implements UserInterface

namespace AppBundle\Entity;

use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;

class User implements UserInterface
{

  // ...

    /**
     * @var \Doctrine\Common\Collections\Collection
     */
    private $userRoles;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->userRoles = new \Doctrine\Common\Collections\ArrayCollection();
    }

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

    /**
     * Геттер для массива ролей.
     *
     * @return array An array of Role objects
     */
    public function getRoles()
    {
        return $this->getUserRoles()->map(function ($item) {
            return $item->getName();
        })->toArray();
    }

    /**
     * @param $roleName
     *
     * @return bool
     */
    public function hasRole($roleName)
    {
        return in_array($roleName, $this->getRoles());
    }

}


I found out that you can load roles into UsernamePasswordToken using re-authenticate the user
Redefining the user token:
$tokenStorage = $this->get('security.token_storage');
        /** @var $user User */
        $user = $tokenStorage->getToken()->getUser();

        $token = new UsernamePasswordToken(
          $user,
          null,
          'main',
          $user->getRoles()
        );
        $this->get('security.token_storage')->setToken($token);

If you do not override the token, $token->getRoles() will only return the ROLE_ADMIN role (I don’t understand where it comes from, presumably, the symphony itself assigns it by default in DEV mode). And after overriding, $token->getRoles() returns all the roles from the database available to the user. Which gives us the opportunity in voters to do this:
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        // ...

        if ($this->decisionManager->decide($token, array('ROLE_DB_SUPER_ADMIN'))) {
            return true;
        }

                // ...
    }

So, the question is, where is it better to redefine the token in Simfony3 (see the code above)? Is this normal practice? As I understand it, it is better to do this redefinition by hanging some kind of kernel-listener. But before doing this, I wanted to know how to do it more competently.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
B
BoShurik, 2017-04-07
@fattan

`provider: main` is not specified in the firewalls.main section. Must be explicitly stated

A
Anton, 2017-04-07
@fattan

The problem was solved when I resorted to the advice of @BoShurik.
But I noticed such a thing (MB is useful to someone) - if you change the name of the role in the database, add a new one, reassign the role of the user, etc. then $this->get('security.token_storage')->getToken()->getRoles() will still return the old list of user roles.
If you clear the cache through the console, or even delete all the cache folders, this will not help. Re-authentication helps (log out, log in). The point is that, at the end of each request, symfony serializes (serializes) the user object into $_SESSOIN, and at the beginning of a new request, it unserializes (unserializes) the object from the session. As I understand it, he also acts with user roles.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question