如何在spring webflux中获取jwt令牌值?(用Minio STS代币兑换)

gst*_*low 9 java spring-security spring-boot minio spring-webflux

我有 spring-boot 应用程序,其中包含使用 Spring Web Flux 编写的其余服务。

现在我使用登录名/密码授权访问 minio,它工作正常。

现在我想用 STS minio 令牌交换应用程序 JWT 令牌,并且我实现了测试方法:

@PostMapping
public boolean test(JwtAuthenticationToken token) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
    MinioClient minioClient =
            MinioClient.builder()
                    .region(...)
                    .endpoint(...)              
                    .credentialsProvider(new WebIdentityProvider(
                           
                            () -> new Jwt(token.getToken().getTokenValue(), 1000),
                            String.valueOf(...),
                            null,
                            null,
                            null,
                            null,
                            null))
                    .build();
    return minioClient.bucketExists("mybucket").build());
}
Run Code Online (Sandbox Code Playgroud)

此代码成功运行并返回,true因为mybucket实际存在。

但这只是测试,我需要进行minioClient配置。这里的问题是我必须在那里有凭证提供者。

所以我创建了以下配置:

@Bean
public MinioClient minioClient() {
    return MinioClient.builder()
            .region(...)
            .endpoint(...)
            .credentialsProvider(new WebIdentityProvider(
                   
                    () -> {
                        String block = null;
                        try {
                            block = ReactiveSecurityContextHolder
                                .getContext()
                                .map(context -> {
                                            return context
                                                    .getAuthentication()
                                                    .getPrincipal();

                                        }
                                )
                                .cast(Jwt.class)
                                .map(Jwt::token)
                                .block();
                        } catch (Exception e) {
                            // it fails here     <=======
                            System.out.println(e);
                        }

                        Jwt jwt = new Jwt(String.valueOf(block),
                                1000);
                        return jwt; },
                    String.valueOf(...),
                    null,
                    null,
                    null,
                    null,
                    null))
            .build();
}
Run Code Online (Sandbox Code Playgroud)

但不幸的是方法block()失败并出现异常:

java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-6 
Run Code Online (Sandbox Code Playgroud)

有什么想法如何修复它吗?

PS_

我试过

.toFuture()
.get();
Run Code Online (Sandbox Code Playgroud)

代替 。block();

但它返回 null

Ely*_*mov 9

正如Numichi在评论中所说,你必须留在反应堆环境中。一种选择是创建类型为 的 bean Mono<MinioClient>

    @Bean
    @Scope(BeanDefinition.SCOPE_PROTOTYPE)
    public Mono<MinioClient> reactiveMinio() {
        return ReactiveSecurityContextHolder.getContext()
                .map(securityContext ->
                        (Jwt)securityContext.getAuthentication().getPrincipal())
                .map(jwt -> MinioClient.builder()
                        .region("someRegion")
                        .endpoint("someEndpoint")
                        .credentialsProvider(webIdentityProvider(jwt.token()))
                        .build());
    }

    private WebIdentityProvider webIdentityProvider(String token) {
        return new WebIdentityProvider(() -> new Jwt(token, 1000),
                "stsEndpoint",
                null,
                null,
                null,
                null,
                null);
    }
Run Code Online (Sandbox Code Playgroud)

我认为 bean 范围应该是原型,因为MinioClient它绑定到安全上下文。

这是反应式的示例用法MinioClient


@RestController
public class MinioTest {

    private Mono<MinioClient> minioClient;

    public MinioTest(Mono<MinioClient> minioClient) {
        this.minioClient = minioClient;
    }

    @GetMapping("/minio")
    public Mono<Object> client() {
        return minioClient
                .map(minio -> {
                    try {
                        return minio.bucketExists(BucketExistsArgs
                                .builder()
                                .bucket("my-bucketname")
                                .build());
                    } catch (Exception e) {
                        return new Exception(e);
                    }
                });
    }
}


Run Code Online (Sandbox Code Playgroud)