Spring Cloud Zuul и токен обновления JWT

У меня есть локальная оркестрованная среда с использованием облачных компонентов Spring (eureka, zuul и серверы аутентификации). Все эти компоненты реализованы как отдельные автономные службы. Затем у меня появляется растущее число комбинированных сервисов пользовательского интерфейса / ресурсов, в которых все отдельные сервисы имеют собственный пользовательский интерфейс. Пользовательский интерфейс составляется на стороне сервера с использованием шаблонов тимелеафа, но по сути представляет собой одностраничные приложения angularjs, которые запускаются в браузере.

Один сервис Zuul обслуживает все сервисы пользовательского интерфейса / ресурсов. Я аннотировал все службы пользовательского интерфейса / ресурсов @EnableResourceServer и добавил @EnableOAuth2Sso на сервер Zuul.

В application.properties для Zuul у меня есть следующие свойства:

security.oauth2.client.accessTokenUri=http://localhost:8771/uaa/oauth/token
security.oauth2.client.userAuthorizationUri=http://localhost:8771/uaa/oauth/authorize
security.oauth2.client.clientId=waharoa
security.oauth2.client.clientSecret=waharoa
security.oauth2.client.preEstablishedRedirectUri=http://localhost:81/login
security.oauth2.client.registeredRedirectUri=http://localhost:81/login
security.oauth2.client.useCurrentUri=false
security.oauth2.resource.jwt.keyValue=-----BEGIN PUBLIC KEY-----[ETC omitted]...

Кажется, все работает так, как рекламируется. Моя проблема в том, когда истекает срок действия токена.

На сервере Auth я установил, что токен истекает через 60 секунд, а токен обновления истекает через 12 часов. Когда срок действия токена истекает, сервер zuul не может получить новый токен.

На сервере zuul это отображается в журнале:

BadCredentialsException: не удается получить действительный токен доступа, выданный OAuth2TokenRelayFilter.getAccessToken

Обновление: я включил отладку для org.springframework.security.oauth в службе Zuul и получил следующее

    17:12:33.279 DEBUG o.s.s.o.c.t.g.c.AuthorizationCodeAccessTokenProvider - Retrieving token from http://localhost:8771/uaa/oauth/token
    17:12:33.289 DEBUG o.s.s.o.c.t.g.c.AuthorizationCodeAccessTokenProvider - Encoding and sending form: {grant_type=[refresh_token], refresh_token=[eyJhbGciOiJS[...deleted...]VgGRHGT8OJ2yDfNVvNA]}
    17:12:37.279 WARN  o.s.c.n.z.f.post.SendErrorFilter - Error during filtering
[blah blah stacktrace many lines omitted]
Caused by: org.springframework.security.authentication.BadCredentialsException: Cannot obtain valid access token
        at org.springframework.cloud.security.oauth2.proxy.OAuth2TokenRelayFilter.getAccessToken(OAuth2TokenRelayFilter.java:99)
        at org.springframework.cloud.security.oauth2.proxy.OAuth2TokenRelayFilter.run(OAuth2TokenRelayFilter.java:79)
        at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112)
        at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:193)
        ... 106 common frames omitted

На стороне службы Auth (uaa) я вижу, как клиент zuul (waharoa) проходит проверку подлинности, получает сведения о правильном пользователе, а затем распечатывает:

17:12:37.288 DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed

Я полагаю, это означает, что сервер аутентификации сделал то, что ему нужно, и ответил на запрос? Похоже, что-то неправильно настроено на сервисе Zuul, есть предложения?

Может ли кто-нибудь посоветовать, какую еще информацию мне нужно опубликовать здесь, чтобы выяснить, почему обновление токена не работает. Я новичок в весеннем облаке, и это соглашение о черной магии не очень понятно (я искал и искал примеры того, что, как я думал, будет обычным вариантом использования, но ничего не нашел).

Примечание 2: у меня уже есть следующий компонент на стороне Zuul

@Bean
    public OAuth2RestTemplate oauth2RestTemplate(OAuth2ProtectedResourceDetails resource, OAuth2ClientContext context) {
        return new OAuth2RestTemplate(resource, context);
    }

Следуя совету @AlexK, я также добавил следующий компонент UserDetailsService на стороне Auth.

@Bean
    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }

И добавил это в конфигурацию моего сервера аутентификации

@Autowired
    private UserDetailsService userDetailsService;

@Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore()).tokenEnhancer(jwtTokenEnhancer())
                .authenticationManager(authenticationManager).userDetailsService(userDetailsService)
            .reuseRefreshTokens(false);
}

Но результат тот же. Refresh_token имеет место, но кажется, что он умирает, когда ответ попадает в фильтр Zuul.

Примечание 3:

@AlexK действительно был на высоте. Я узнал, что когда токен обновляется, он не просто обновляется из хранилища токенов, он требует вызова базового UserDetailsService, чтобы снова получить данные пользователя. Поскольку я получал подробную информацию из Active Directory, для решения этой проблемы потребовалось много проб и ошибок, но теперь она работает так, как рекламируется. Мой (отсутствующий) простой bean-компонент UserDetailsService, который был автоматически подключен к конфигурации, как показано в примечании 2:

@Bean(name = "ldapUserDetailsService")
public UserDetailsService userDetailsService() {
    FilterBasedLdapUserSearch userSearch = new FilterBasedLdapUserSearch(searchBase, "(sAMAccountName={0})",
            contextSource());
    LdapUserDetailsService result = new LdapUserDetailsService(userSearch);
    result.setUserDetailsMapper(new InetOrgPersonContextMapper());
    return result;
}

person LukeM    schedule 20.08.2017    source источник


Ответы (1)


Я думаю, что все необходимые подсказки находятся в этом вопросах и ответах

Суммируя:

  1. Подсказка - необходимо реализовать OAuth2RestTemplate на вашей стороне Zuul / UIApp. Как сказано в Ссылка на Spring Boot по умолчанию не создается.
  2. Другая часть находится внутри этого ответа - необходимо внести определенные изменения на стороне OAuth-сервера.

После этого вы автоматически обновите свой access_token с помощью refresh_token.

P.S. Но когда срок действия токена refresh_token истекает, вы все равно можете получить такую ​​же ошибку! Чтобы справиться с этим, вы можете сделать так, чтобы ваш refresh_token автоматически обновлялся одновременно с получением нового access_token. Используйте reuseRefreshTokens (false) в конфигурации AuthorizationServerEndpointsConfigurer в коде аутентификационного сервера:

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
        throws Exception {
    endpoints
        .authenticationManager(authenticationManager)
        .userDetailsService(userDetailsService)
        .reuseRefreshTokens(false); // <--that's the key to get new refresh_token at the same time as new access_token
}

Более подробно объяснено здесь

person AlexK    schedule 21.08.2017
comment
Спасибо за ваш ответ. У меня уже есть OAuth2RestTemplate на стороне Zuul. Я заметил, что ИНФОРМАЦИЯ из авторизации говорит об отсутствии UserDetailsService, поэтому я добавил это в соответствии с вашей ссылкой. К сожалению, я все еще получаю тот же результат. Процесс токена обновления) вроде работает нормально, но Zuul Filter по-прежнему генерирует исключение. Я до сих пор не знаю, почему это так. - person LukeM; 22.08.2017
comment
вы были точны. Возникла проблема с моей UserDetailsService. - person LukeM; 22.08.2017
comment
поздравляю! Возможно, будущим читателям будет полезно узнать, какая у вас проблема с UserDetailsService. мне тоже интересно - person AlexK; 22.08.2017
comment
Я добавил примечание об обновлении к вопросу, чтобы включить код, который мне нужно было добавить для подключения к Active Directory. Спасибо еще раз. - person LukeM; 23.08.2017