Перезагрузить роль пользователя после изменения без повторной регистрации - PullRequest
0 голосов
/ 18 марта 2019

Как обновить зарегистрированную роль пользователя, например, когда она была изменена администратором?Я нашел параметр безопасности always_authenticate_before_granting (он не включен в документацию по Symfony 4) и установил для него true.

security.yaml:

security:
    always_authenticate_before_granting: true
    encoders:
        App\Entity\Main\User:
            algorithm: bcrypt

    providers:
        app_user_provider:
            entity:
                class: App\Entity\Main\User
                property: email
    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: ~
            guard:
                authenticators:
                    - App\Security\LoginFormAuthenticator
            form_login:
                login_path: login
                check_path: login
            logout:
                path: logout
                target: homepage
            remember_me:
                secret:   '%kernel.secret%'
                path:     /
    access_control:
        - { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/.*, roles: ROLE_USER }

, но это не такне вступает в силу.

ОБНОВЛЕНИЕ

Я создал подписчика onRequest:

class RequestSubscriber implements EventSubscriberInterface
{
    private $tokenStorage;

    public function __construct(TokenStorageInterface $tokenStorage)
    {
        $this->tokenStorage = $tokenStorage;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::REQUEST => 'onRequest'
        ];
    }

    public function onRequest(GetResponseEvent $event): void
    {
        if (!$event->isMasterRequest()) {
            return;
        }

        if(!$token = $this->tokenStorage->getToken()) return;

        $sessionUser = $token->getUser();

        if ($sessionUser instanceof User) {
            $this->tokenStorage->setToken(new PostAuthenticationGuardToken($sessionUser, 'main', $sessionUser->getRoles()));
        }
    }
}

, и теперь я могу обновлять обновленные роли по каждому запросу, но сравнивая sessionUser с databaseUserбессмысленно, потому что sessionUser всегда содержит недавно обновленные роли, хотя в Symfony Profiler> Security Token перечислены старые (конечно, если я не установил новый токен).

1 Ответ

1 голос
/ 18 марта 2019

Tl; dr Я боюсь, что вам придется ввести собственный механизм, чтобы сделать эту работу.

Токен сеанса хранится внутри сеанса пользователя.Это окажет значительное влияние на производительность вашего приложения, потому что каждый раз, когда требуется запрос к базе данных, чтобы проверить, изменилась ли роль.

Поэтому вам потребуется обработчик запросов который будет сравнивать роль базы данных с текущей ролью пользователя и, если она не совпадает, заменить токен в сеансе, на этот раз новым списком ролей, например.(псевдокод):

sessionUser = tokenStorage.token.user
databaseUser = userRepository.find(sessionUser.id)

if sessionUser.roles !== databaseUser.roles
    tokenStorage.setToken(new PostAuthenticationGuardToken(…))

или использовать кеш в качестве носителя флага для уведомления пользователя об изменении.Этот метод наверняка будет намного быстрее.

sessionUser = tokenStorage.token.user

// of course the flag has to be set when the user's role gets changed
cacheToken = 'users.role_reload.' . sessionUser.id

if cache.has(cacheToken)
    databaseUser = userRepository.find(sessionUser.id)
    tokenStorage.setToken(new PostAuthenticationGuardToken(…))
    cache.remove(cacheToken)

В любом случае пользователь должен спросить приложение, было ли изменение роли при каждом запросе.

...