Как установить локаль пользователя на запомненном логине в Symfony? - PullRequest
0 голосов
/ 30 апреля 2018

Я работаю над проектом Symfony 2.8. Веб-страница может использоваться на разных языках, а выбранный язык сохраняется в Session. Используя класс Locale Listener, можно без проблем установить правильный языковой стандарт, когда пользователь заходит на страницу или входит в систему:

class LocaleListener implements EventSubscriberInterface {
    private $defaultLocale;

    public function __construct($defaultLocale = 'de') {
        $this->defaultLocale = $defaultLocale;
    }

    public static function getSubscribedEvents() {
        return array(
            // must be registered before the default Locale listener
            KernelEvents::REQUEST => array(array('onKernelRequest', 17)),
            SecurityEvents::INTERACTIVE_LOGIN => array(array('onSecurityInteractiveLogin', 18)),                
            AuthenticationEvents::AUTHENTICATION_SUCCESS => 'onAuthenticationSuccess',
        );
    }

    public function onKernelRequest(GetResponseEvent $event) {
        $request = $event->getRequest();

        if (!$request->hasPreviousSession()) 
            return;

        if ($locale = $request->attributes->get('_locale')) {            
            // try to see if the locale has been set as a _locale routing parameter    
            $request->getSession()->set('_locale', $locale);
        } else {
            // if no explicit locale has been set on this request, use one from the session            
            $request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));
        }
    }

    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event) {
        // ...get locale from user settings and it info to session...
    }

    public function onAuthenticationSuccess(AuthenticationEvent $event) {
        // ...get locale from user settings and it info to session...
    }
}

Это тот же код, что и в документациях Symfony , расширенных слушателями входа в систему. Он прекрасно работает, когда пользователь активно входит в систему. В этом случае срабатывают и SecurityEvents::INTERACTIVE_LOGIN, и AuthenticationEvents::AUTHENTICATION_SUCCESS (Кстати: в чем разница между этими двумя)?

Однако если пользователь вошел в систему и получил доступ к странице, ни одно из двух событий не сработало.

Это проблема, когда сеанс истек, а cookie remember_me - нет. Я сталкивался при обновлении страницы в браузере после того, как несколько дней не работал на этом компьютере: cookie remember_me все еще был активен, и, таким образом, пользователь все еще входил в систему. Однако страница была обновлена ​​на языке по умолчанию и не на языке пользователя, что возможно только тогда, когда время сеанса истекло в то время как ...

Я не настроил время жизни сеанса в файле конфигурации, и панель инструментов отладки Symfony показывает время жизни сеанса 0. Конечно, я мог бы продлить время жизни и сделать его дольше, чем время жизни параметра Remember_me. Однако было бы намного более чистым решением перечитывать локаль из пользовательских настроек каждый раз, когда пользователь проходит аутентификацию.

Я предполагаю, что аутентификация выполняется при каждом отдельном запросе. Либо через учетные данные пользователя, которые отправляются через форму входа (= интерактивный вход в систему), либо с помощью информации, хранящейся в файле cookie remember_me. Разве это не правильно?

В этом случае я бы ожидал, что событие AuthenticationEvents::AUTHENTICATION_SUCCESS запускается при каждом запросе. Но, похоже, это не так.

Короче говоря:

Как я могу убедиться, что локаль из пользовательских настроек используется, пока пользователь вошел в систему?

1 Ответ

0 голосов
/ 30 апреля 2018

Исходя из моего опыта, каждый раз, когда мы делаем запрос (если аутентификация основана на сеансе), Symfony проверяет, совпадает ли запрос с каким-либо активным сеансом (используя некоторый файл cookie в качестве идентификатора сеанса или что-то подобное). Если это так, то запускается onAuthenticationSuccess, в противном случае вы будете перенаправлены на страницу входа. После того, как форма входа в систему и если учетные данные пользователя действительны, вы проходите проверку подлинности и запускается onSecurityInteractiveLogin.

Итак, onAuthenticationSuccess срабатывает, если учетные данные действительны в каждом запросе, а onSecurityInteractiveLogin срабатывает только при успешной регистрации входа. В любом случае после успешной аутентификации вы перенаправляетесь на целевой URL во время событий ядра, начиная с события onKernelRequest.

Итак, я думаю, что проблема может заключаться в том, что когда происходит успешное onAuthenticationSuccess, вы фактически вводите язык пользователя в сеанс, но после этого запускается onKernelRequest, и вы перезаписываете эту информацию с помощью

$request->setLocale($request->getSession()->get('_locale', $this->defaultLocale));

Если это проблема, рассмотрите возможность установки языка только в событии onSecurityInteractiveLogin

...