Я видел похожие темы, но моя отличается тем, что я использую пользовательские grant type
. Чтобы дать вам представление, когда мы вызываем микросервис из другого, мы используем токен delegation
, в котором есть данные о пользователе, который инициировал вызов. Поэтому пользователь U1 звонит S1 и S1 , звонит S2 , поэтому S2 использует U1 детали для целей аудита и разрешений.
Теперь, чтобы достичь этого, у нас есть следующая конфигурация для OAuth2RestTemplate
:
@Bean(name = "delegationResource")
@Autowired
public OAuth2ProtectedResourceDetails delegationResource(OAuth2ClientAuthenticationSettings settings) {
OAuth2AuthenticationSettings authSettings = authenticationSettings != null ? authenticationSettings : new OAuth2AuthenticationSettings();
StringBuilder url = new StringBuilder();
url.append(settings.getAuthorisationUrl() != null ? settings.getAuthorisationUrl() : authSettings.getUrl());
url.append(settings.getAccessTokenPath());
DelegationResourceDetails details = new DelegationResourceDetails(authenticationFacade);
details.setClientId(settings.getClientId());
details.setClientSecret(settings.getClientSecret());
details.setAccessTokenUri(url.toString());
details.setGrantType("custom");
if(settings.getScopes() != null) {
details.setScope(Arrays.asList(settings.getScopes()));
}
return details;
}
@Bean(name = "requestScopeClientContext")
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) //Without request-scope, RestTemplate is not thread-safe
public OAuth2ClientContext requestScopeClientContext() {
//This is used for delegation requests and needs to be scoped as request otherwise the first token will be used for all other subsequent calls regardless of what user is initiating it
return new DefaultOAuth2ClientContext();
}
@Autowired
CorrelationIDInterceptor correlationIDInterceptor;
@Bean(name = "delegationOauth2RestTemplate")
//if access to a third party resource is required, a new bean should be created with a @Qualifier
@Autowired
public OAuth2RestTemplate clientCredentialDelegationOauth2RestTemplate(@Qualifier("delegationResource") OAuth2ProtectedResourceDetails delegationResource, @Qualifier("requestScopeClientContext") OAuth2ClientContext sessionScopeClientContext) {
/*
This is used to send requests from a micro-service to another on behalf of the user who initiated the original request
so this has to have a thread-safe client-context
*/
ArrayList<ClientHttpRequestInterceptor> clientHttpRequestInterceptors = new ArrayList<>();
clientHttpRequestInterceptors.add(correlationIDInterceptor);
DelegationOAuth2RestTemplate delegationOAuth2RestTemplate = new DelegationOAuth2RestTemplate(delegationResource, sessionScopeClientContext);
delegationOAuth2RestTemplate.setInterceptors(clientHttpRequestInterceptors);
return delegationOAuth2RestTemplate;
}
Как видите, OAuth2ClientContext
должен быть в request
область действия, в противном случае будут использоваться предыдущие данные пользователя, и генерация токенов для второго пользователя не произойдет и т. Д.
Но это оказывает некоторое влияние на производительность. Эффект становится более заметным, когда у нас много одновременно работающих пользователей. Поэтому в качестве решения я собираюсь кэшировать OAuth2ClientContext
на пользователя с установленным значением срока действия кэша, которое меньше значения срока действия токена. Хотя истечение срока действия кэша на самом деле не является проблемой, потому что каждый токен будет проверен до получения этой точки.
Теперь вопрос в том, как мне этого добиться и как лучше? Насколько я понимаю, мне нужно изменить область действия с request
на singleton
, как область действия стандартного бина Spring, а затем каким-то образом создать его, чтобы создать новый экземпляр, когда в кэше нет записи? Не знаете, как это сделать?