我见过类似的线程,但我的不同之处在于我使用的是自定义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
每个用户,并将缓存到期设置为小于令牌到期的值。尽管缓存过期并不是真正的问题,因为每个令牌都会在得到这一点之前进行验证。
现在的问题是我如何实现这一目标,最好的方法是什么?根据我的理解,我需要将范围从默认 Spring bean 的范围更改request
为singleton
类似,然后在缓存中没有条目时以某种方式使其创建一个新实例?不知道如何做到这一点?