hwi_oauth Запомнить меня и IS_AUTHENTICATED_FULLY

Я работаю над добавлением входа Oauth на сайт Symfony2. У меня есть пакет, работающий и настроенный с PayPal и Facebook. Я помню, как работал. Моя проблема заключается в том, что когда пользователь возвращается через «запомнить меня» и пытается повторно аутентифицироваться через oauth, он сообщает мне, что учетные записи были полностью подключены, но не аутентифицирует меня вообще. Повторный вход с именем пользователя и паролем работает нормально.

Config.yml

hwi_oauth:
    # name of the firewall in which this bundle is active, this setting MUST be set
    firewall_name: main
    connect:
        account_connector: app.provider.oauth
        confirmation: true
    resource_owners:
        facebook:
            type:                facebook
            client_id:           %facebook_client_id%
            client_secret:       %facebook_client_secret%
            scope:               "email, public_profile"
            infos_url:           "https://graph.facebook.com/me?fields=id,name,first_name,last_name,email,picture.type(large)"
            paths:
                email: email
            options:  
                csrf: true           
        paypal:
            type:                paypal
            client_id:           %paypal_client_id%
            client_secret:       %paypal_client_secret%
            scope: 'openid profile email'
            options: 
                csrf: true

Security.yml

firewalls:
        main:
            pattern: ^/
            anonymous: ~
            oauth:
                failure_path: /login
                login_path:  /login
                check_path: /login
                provider: fos_userbundle
                remember_me:  true
                always_use_default_target_path: false
                default_target_path: /login
                resource_owners:
                    facebook: "/external-login/check-facebook"
                    paypal: "/external-login/check-paypal"
                    amazon: "/external-login/check-amazon"
                oauth_user_provider:
                    service: app.provider.oauth
                remember_me:
                    key:      %secret% 
                    lifetime: 31536000  
                    path:     /
                    domain:   ~
                    always_remember_me: true
            form_login:
                login_path:  /login
                check_path:  /login_check
                success_handler: authentication_handler
                failure_handler: authentication_handler
                csrf_provider: form.csrf_provider
                remember_me:  true
            logout:       true
            anonymous:    true
            switch_user: { role: ROLE_ALLOWED_TO_SWITCH, parameter: _new_user }
            remember_me:
                key:      %secret% 
                lifetime: 31536000 
                path:     /
                domain:   ~
                always_remember_me: true

Маршрутизация.yml

hwi_oauth_redirect:
    resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml"
    prefix:   /connect

hwi_oauth_login:
    resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
    prefix:   /external-login/

hwi_oauth_connect:
    resource: "@HWIOAuthBundle/Resources/config/routing/connect.xml"
    prefix:  /external-login/

facebook_login:
    pattern: /external-login/check-facebook

paypal_login:
    pattern: /external-login/check-paypal

Спасибо!


person Jeremy    schedule 15.08.2016    source источник
comment
Привет @Jeremy, есть новости по этому вопросу? Вы решили эту проблему? Думаю, у меня возникла та же проблема abstractresourceowner содержит ошибки"> stackoverflow.com/questions/53212879/   -  person Nadjib    schedule 08.11.2018
comment
Это было небрежно, но я изменил библиотеку поставщика, как показано здесь: / Я не думаю, что они одобрили это и добавили поддержку самостоятельно.   -  person Jeremy    schedule 09.11.2018
comment
То есть вы имеете в виду, что добавили измененные части в код поставщика? Это хорошая практика? Это работает хорошо? Я имею в виду, позволяет ли это вам использовать автономный режим Google OAUth? Заранее спасибо,   -  person Nadjib    schedule 09.11.2018
comment
Вам действительно не следует изменять части кода поставщика, если вы не уверены на 100%, что он будет принят в основной репо, или вы никогда не будете обновлять библиотеку. У нас это работало нормально, пока мы не перестроили/переключили платформы для нашего сайта. Я понятия не имею, что такое автономный режим Google OAUTH.   -  person Jeremy    schedule 09.11.2018


Ответы (1)


Мой собственный ответ (решено)

Итак, я наконец нашел решение своей проблемы, возможно, это поможет другим решить ее.

Вот почему токен не прошел аутентификацию.

Для возвращающегося пользователя на моей домашней странице я назвал is_granted('ROLE_ADMIN'), поэтому токен был аутентифицирован методом authenticate из AuthenticationManager, который был вызван в AuthorizationChecker, как вы можете видеть ниже.

final public function isGranted($attributes, $object = null)
    {
        if (null === ($token = $this->tokenStorage->getToken())) {
            throw new AuthenticationCredentialsNotFoundException('The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.');
        }

        if ($this->alwaysAuthenticate || !$token->isAuthenticated()) {
            $this->tokenStorage->setToken($token = $this->authenticationManager->authenticate($token));
        }

        if (!\is_array($attributes)) {
            $attributes = array($attributes);
        }

        return $this->accessDecisionManager->decide($token, $attributes, $object);
    }

Затем AuthenticationManager использует метод authenticate из OAuthProvider, который является одной из его зависимостей. Этот метод выглядит следующим образом:

 * {@inheritdoc}
 */
public function authenticate(TokenInterface $token)
{
    if (!$this->supports($token)) {
        return;
    }

    // fix connect to external social very time
    if ($token->isAuthenticated()) {
        return $token;
    }

    /* @var OAuthToken $token */
    $resourceOwner = $this->resourceOwnerMap->getResourceOwnerByName($token->getResourceOwnerName());

    $oldToken = $token->isExpired() ? $this->refreshToken($token, $resourceOwner) : $token;
    $userResponse = $resourceOwner->getUserInformation($oldToken->getRawToken());

    try {
        $user = $this->userProvider->loadUserByOAuthUserResponse($userResponse);
    } catch (OAuthAwareExceptionInterface $e) {
        $e->setToken($oldToken);
        $e->setResourceOwnerName($oldToken->getResourceOwnerName());

        throw $e;
    }

    if (!$user instanceof UserInterface) {
        throw new AuthenticationServiceException('loadUserByOAuthUserResponse() must return a UserInterface.');
    }

    $this->userChecker->checkPreAuth($user);
    $this->userChecker->checkPostAuth($user);

    $token = new OAuthToken($oldToken->getRawToken(), $user->getRoles());
    $token->setResourceOwnerName($resourceOwner->getName());
    $token->setUser($user);
    $token->setAuthenticated(true);
    $token->setRefreshToken($oldToken->getRefreshToken());
    $token->setCreatedAt($oldToken->getCreatedAt());

    return $token;
}

Как видите, для возвращающегося пользователя срок действия OAuthToken истек, поэтому OAuthProvider попытается обновить его.

$oldToken = $token->isExpired() ? $this->refreshToken($token, $resourceOwner) : $token;

Моя проблема заключалась в том, что мой предыдущий OAuthToken имел нулевую опцию refresh_token. Хотя я установил access_type на offline на моем config.yml для HWIOAuthBundle, это не сработает, Refresh_token по-прежнему будет нулевым.

hwi_oauth
    resource_owners:
        google:
            type: google
            client_id: "%google_app_id%"
            client_secret: "%google_app_secret%"
            scope: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/user.birthday.read"
            options:
                access_type: offline
                prompt: consent

Так почему же мой refresh_token всегда был нулевым? Я упал на этот другой вопрос о стеке через поток Не получает токен обновления Google OAuth

Ответы точно расскажут вам, почему Google не отправляет вам refresh_token. После того, как вы использовали аутентификацию OAuth без refresh_token, Google никогда не отправит вам токен обновления, если вы не запросите согласие APi.

Вот почему я добавил prompt: consent в свой файл конфигурации.

Так почему же все это породило ошибку?

Если я не получу Refresh_token из API Google, userResponse из OAuthProvider, который основан на ответе API Google, будет иметь нулевой атрибут username.

$userResponse = $resourceOwner->getUserInformation($oldToken->getRawToken());

Поэтому, когда OAuthProvider пытается загрузить пользователя благодаря OAuthUserProvider, имя пользователя будет нулевым, поэтому OAuthUserProvider не найдет пользователя.

$user = $this->userProvider->loadUserByOAuthUserResponse($userResponse);

Поэтому мне нужно было получить от google refresh_token, чтобы получить правильный userResponse с непустым атрибутом username.

Изменение моей конфигурации для hwi_oauth и добавление этих двух параметров в google ressource_owners решило мою проблему.

options:
    access_type: offline
    prompt: consent
person Nadjib    schedule 19.11.2018