简体   繁体   中英

How to get jwt token value in spring webflux? (to exchange it with Minio STS token)

I have sping-boot application with rest services written using Spring web flux.

For now I access minio using login/password authorizaton and it works fine.

For now I want to exchange application JWT token with STS minio token and I implemented method to test:

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

This code successfully works and returns true because mybucket actually exists.

But it is only test and I need to move minioClient to the configuration. The issue here that I have to have credentials provider there.

So I've created folowing configuration:

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

But unfortunately method block() fails with exception:

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

Any ideas how to fix it?

As Numichi stated in the comment you have to stay in the reactor context. One option is to create a bean of type 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);
    }

I think bean scope should be prototype since MinioClient is bound to security context.

Here is the sample usage of reactive 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);
                    }
                });
    }
}


The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM