Как настроить OAuth2RestTemplate с учетными данными клиента и автоматическим обновлением токена в spring-security-oauth 2.2.1.RELEASE
Я внедряю клиента, который аутентифицируется с помощью OAuth2 против WSO2, и у меня серьезные проблемы с обновлением токена доступа, получая 401 НЕСАНКЦИОНИРОВАННО. Хотя я уже выяснил, что делает код Spring OAuth2, я не знаю, почему его поведение было изменено в 2.2.1.RELEASE, и мне кажется, что это неправильно. На самом деле с помощью 2.0.14. РЕЛИЗ работает.
Прежде чем я покажу вам, что я сделал и что я уже выяснил, позвольте мне сформулировать свой вопрос:
Как мне реализовать клиент OAuth2 с автоматическим обновлением токена с учетными данными клиента вместо учетных данных пользователя?
Так вот, что я реализовал до сих пор. Клиент настраивает OAuth2RestTemplate
с ResourceOwnerPasswordResourceDetails
с isClientOnly
флаг true
, так как нет пользовательских сессий. Сеанс клиента может быть успешно установлен, а также установлены токен доступа и токен обновления.
@Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails() {
@Override
public boolean isClientOnly() {
return true;
}
};
List<String> scopes = new ArrayList<>(2);
scopes.add("write");
scopes.add("read");
resource.setScope(scopes);
resource.setGrantType("password");
resource.setAccessTokenUri(TOKEN_URL);
resource.setClientId(MY_CLIENT_ID);
resource.setClientSecret(MY_CLIENT_SECRET);
resource.setUsername(MY_SERVICE_USER);
resource.setPassword(MY_SERVICE_USER_PW);
return resource;
}
@Bean
public OAuth2RestOperations restTemplate() {
AccessTokenRequest atr = new DefaultAccessTokenRequest();
OAuth2RestTemplate template = new OAuth2RestTemplateWithBasicAuth(resource(), new DefaultOAuth2ClientContext(atr));
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
interceptors.add(new LoggingRequestInterceptor());
template.setInterceptors(interceptors);
template.setRetryBadAccessTokens(true);
return template;
}
Все идет нормально. Я убедился, что это в основном работает.
Но как только истекает токен доступа, я часто сталкиваюсь с ошибками 401, потому что обновление токена не выполняется. Вместо этого выполняется обычный запрос аутентификации, но с использованием клиентского ключа и секрета вместо имени пользователя / пароля. Короче говоря, я отладил свой путь через spring-security-oauth2 в AccessTokenProviderChain#obtainAccessToken
и выяснил, что выполняется ли запрос на обновление токена, определяется следующим фрагментом кода. Смотрите на Github
if (resource.isClientOnly() || (auth != null && auth.isAuthenticated())) { // P1
existingToken = request.getExistingToken();
if (existingToken == null && clientTokenServices != null) {
existingToken = clientTokenServices.getAccessToken(resource, auth);
}
if (existingToken != null) {
if (existingToken.isExpired()) {
if (clientTokenServices != null) {
clientTokenServices.removeAccessToken(resource, auth);
}
OAuth2RefreshToken refreshToken = existingToken.getRefreshToken();
if (refreshToken != null && !resource.isClientOnly()) { // P2
accessToken = refreshAccessToken(resource, refreshToken, request);
}
}
else {
accessToken = existingToken;
}
}
}
Как вы можете видеть на P1, блок вводится, если существует сеанс авторизованного пользователя (auth
) или ресурс настроен как clientOnly
, Поскольку у меня нет пользователей, но я нахожусь в связанном сценарии службы, у меня есть isClientOnly() == true && auth == null
, Но на P2 окончательное решение по фактическому обновлению противоречит требованию !isClientOnly()
, Таким образом, это эффективно запрещает запросы на обновление в клиентских сценариях.
Это был путь в версиях до 2.2.1, и я обнаружил, что это, кажется, исправление следующей проблемы. Мне это кажется совершенно неправильным.
Кроме того, мне кажется, что патч нарушает функциональность клиента, чтобы исправить фактическое неправильное поведение сервера. Как вы можете видеть в обсуждении проблемы, я уже прокомментировал там. Но так как эта проблема закрыта, и форум spring-security-oauth2 утверждает, что здесь, на Stackru, должны быть проведены обсуждения, я прошу помощи здесь.
Снова вопрос: как клиентское приложение должно быть настроено на использование защищенных сервисов OAuth2 через OAuth2RestTemplate и время работы токена доступа в час и время обновления токена, скажем, два часа.