Смешанный токен доступа в приложении Spring WebMVC с использованием Spring Security oAuthClient

Я использую Spring Spring Boot / Security 5.4.8 с oAuth2-Client.

В моем приложении есть фоновая обработка (пул потоков с 3 параллельными заданиями). Часть каждого задания использует удаленную службу ReST

  • который требует Jwt-аутентификации
  • в зависимости от контекста арендатора задания, необходима другая область действия (если задание обрабатывается для арендатора A, область действия должна быть A и так далее ...)

В тривиальном сценарии обрабатываются только задания одного клиента, и токен доступа можно использовать повторно все время (до обновления). Это прекрасно работает.

Но при работе с разными арендаторами токен доступа должен быть изменен. К сожалению, токены доступа перепутались. Означает, что запрос задания 1 (арендатор A) содержит AT арендатора 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) ->
            oAuth2AuthorizedClientService.saveAuthorizedClient(authorizedClient, principal));
        authorizedClientManager.setAuthorizationFailureHandler(
            new RemoveAuthorizedClientOAuth2AuthorizationFailureHandler(
                (clientRegistrationId, principal, attributes) ->
                    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 List<ClientRegistration> registrations = new ArrayList<>(OAuth2ClientPropertiesRegistrationAdapter.getClientRegistrations(properties).values());
        final ClientRegistrationRepository parent = new InMemoryClientRegistrationRepository(registrations);

    return (registrationId) -> {
        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() {
        List<Job> jobs = this.mockService.getJobs();
        jobs.forEach(job -> this.jobExecutor.process(job));
    }
}

@Component
public class JobExecutor {

    @Async("threadPoolTaskExecutor")
    public CompletableFuture<JobState> 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();
    }

}

0 ответов