1

我正在使用带有 oAuth2-Client 的 spring Spring Boot / Security 5.4.8。

我的应用程序具有后台处理(具有 3 个并行作业的线程池)。每个作业的一部分都在使用远程 ReST 服务

  • 这需要 Jwt 身份验证
  • 根据作业的租户上下文,需要不同的范围(如果为租户 A 处理作业,范围必须是 A,依此类推...)

在一个简单的场景中,只处理一个租户的作业,并且访问令牌可以一直重复使用(直到刷新)。这工作正常。

但是对于不同租户的工作,必须更改访问令牌。不幸的是,访问令牌混淆了。表示作业 1(租户 A)的请求包含租户 B 的 AT,依此类推。当访问令牌映射工作以及混淆时,我没有观察到任何确定性行为。

我的条带化代码如下所示。

你对如何解决这个问题有什么建议吗?还是我在做任何概念上的失败?

@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();
    }

}

4

0 回答 0