null principal returned by ServerRequest in webflu

2020-07-17 07:54发布

问题:

I have set up authentication in a Spring WebFlux application. The authentication mechanism appears to work fine. For example the following code is used to set up security web filter chain:

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {

    return http.authorizeExchange()
            .pathMatchers("/path/to/resource").hasAuthority("A_ROLE")
            .anyExchange().authenticated()
            .and().httpBasic()
            .and().build();
}

This works as expected in conjunction with the UserDetailsRepositoryReactiveAuthenticationManager and MapReactiveUserDetailsService. If a user doesn't have the required authority a forbidden error code is returned and otherwise the request is passed on to the handler.

I have a requirement to apply fine grained permission checks within the handler itself and figured that I should be able to retrieve the authorities from the request as follows:

public Mono<ServerResponse> getMyResource(ServerRequest serverRequest) {

      Authentication authentication = (Authentication)serverRequest.principal().block();
      ...   
}

However, I find that the principal is always null. First, is this the correct way to get a handle on the authorities, and if so is there possibly some upstream configuration I'm missing?

回答1:

You are blocking the result before is available. You can simply flatmap it so that you don't have to block it.

public Mono<ServerResponse> getMyResource(ServerRequest serverRequest) {
    return serverRequest.principal().flatMap((principal) -> ServerResponse.ok()
            .body(fromObject("Hello " + principal.getName())));
}

UPDATE: If you want to retrieve the principal and body you could zip them.

public Mono<ServerResponse> getMyResource(ServerRequest serverRequest) {
    return Mono.zip(
            serverRequest.principal(),
            serverRequest.bodyToMono(String.class)
    ).flatMap(tuple -> {
        Principal principal = tuple.getT1();
        String body = tuple.getT2();
        return ServerResponse.ok().build();
    });
}