#multithreading #spring-security #spring-webclient #spring-boot-starter-oauth2-client
#многопоточность #весна-безопасность #весна-веб-клиент #пружинный загрузчик-стартер-oauth2-клиент
Вопрос:
Я использую spring Spring Boot / Security 5.4.8 с OAuth2-клиентом.
В моем приложении есть фоновая обработка (пул потоков с 3 параллельными заданиями). Частью каждого задания является использование службы удаленного отдыха
- для чего требуется Jwt-Аутентификация
- в зависимости от контекста клиента задания необходима другая область (если задание обрабатывается для клиента A, область должна быть A и так далее…)
В тривиальном сценарии обрабатываются только задания одного клиента, и маркер доступа может быть использован повторно все время (до обновления). Это прекрасно работает.
Но с заданиями разных арендаторов маркер доступа должен быть изменен. К сожалению, токен доступа перепутался. Означает, что запрос задания 1 (Арендатор A) содержит запрос Арендатора B и так далее. Я не наблюдал никакого детерминированного поведения, когда работает сопоставление маркеров доступа и когда оно путается.
Мой полосатый код выглядит следующим образом.
У вас есть какие-либо предложения, как подойти к этой проблеме? Или я совершаю какие-то концептуальные ошибки?
@Configuration public class CommonConfig { @Bean OAuth2AuthorizedClientManager defaultAuthClientManager( ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientService oAuth2AuthorizedClientService) { OAuth2AuthorizedClientProvider authorizedClientProvider = new ClientCredentialsOAuth2AuthorizedClientProvider(); var authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager( clientRegistrationRepository, oAuth2AuthorizedClientService); authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); authorizedClientManager.setAuthorizationSuccessHandler((authorizedClient, principal, attributes) -gt; oAuth2AuthorizedClientService.saveAuthorizedClient(authorizedClient, principal)); authorizedClientManager.setAuthorizationFailureHandler( new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler( (clientRegistrationId, principal, attributes) -gt; oAuth2AuthorizedClientService.removeAuthorizedClient(clientRegistrationId, principal.getName()))); return authorizedClientManager; } @Bean(name = "threadPoolTaskExecutor") public TaskExecutor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.initialize(); return executor; } @Bean public ClientRegistrationRepository clientRegistrationRepository(OAuth2ClientProperties properties) { final Listlt;ClientRegistrationgt; registrations = new ArrayListlt;gt;(OAuth2ClientPropertiesRegistrationAdapter.getClientRegistrations(properties).values()); final ClientRegistrationRepository parent = new InMemoryClientRegistrationRepository(registrations); return (registrationId) -gt; { final ClientRegistration clientRegistration = parent.findByRegistrationId("TEMPLATE"); if (clientRegistration == null) { return null; } return ClientRegistration.withClientRegistration(clientRegistration) .registrationId(registrationId) .scope(resultingScopes) .build(); }; } @Component public class JobScheduler { @Scheduled(cron = "0/10 * * * * *") public void trigger() { Listlt;Jobgt; jobs = this.mockService.getJobs(); jobs.forEach(job -gt; this.jobExecutor.process(job)); } } @Component public class JobExecutor { @Async("threadPoolTaskExecutor") public CompletableFuturelt;JobStategt; processJob(Job job) { try{ SecurityContextHolder.getContext().setAuthentication(job.getAuth()); this.myService.getMyRemoteServiceResponse(job.getId()); } finally { SecurityContextHolder.getContext().setAuthentication(null); } } } @Service public class MyService { public MyService(WebClient.Builder webClientBuilder) { ... } private WebClient getWebClient(String scope) { ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client = new ServletOAuth2AuthorizedClientExchangeFilterFunction( authorizedClientManager); oauth2Client.setDefaultClientRegistrationId(scope); return webClientBuilder .apply(oauth2Client.oauth2Configuration()) .build(); } public String getMyRemoteServiceResponse(long id) { String tenantName = SecurityContextHolder.getContext().getAuthentication().getName(); return this.getWebClient(tenantName) .method(httpMethod) .uri(uri) .attributes(oauth2AuthorizedClient(this.getAuthorizedClient(this.getAuthenticationName()))) .retrieve() .bodyToMono(String.class) .block(); } }