Search code examples
javaspringspring-bootspring-securityspring-webflux

How to customize the default unauthorized response body in Spring Security Webflux?


I'm starting a new project using Spring boot Webflux, but now i can't figure it out how to handle 401 responses.

I'd want to return a message body with the response code. The response code is OK and working as expected. Now, how do I inject the message body to give a more verbose and descriptive response as below.

{
    "statusCode": "401",
    "statusMessage": "Unauthorized",
    "timestamp": "Sun May 07 10:30:23 GMT 2023"
}

This is part of my spring security config class:

@Bean
public SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) {
    return http
            .cors().and()
            .csrf().disable()
            //Disable Sessions
            .securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
            // handlers for 401 to return a 401 status, message and timestamp

            //rest services don't have a login form
            .formLogin()
            .disable()
            .authorizeExchange()
            .pathMatchers("/api/v1/get-token").hasRole("API")
            .and()
            .httpBasic()
            .and()
            .build();
}

Everything works well, I just want to return a message body JSON not just the HTTP reponse code. Anyone?


Solution

  • Provide one solution that use the entryPoint which is provided by security . The corresponding code snippet like following .

    1.Custom a EntryPoint

    public class CustomAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
    
        @Override
        public Mono<Void> commence(ServerWebExchange exchange, AuthenticationException authException) {
            // Custom error message or response body
            String errorMessage = "Unauthorized. Please authenticate.";
    
            // Set the status code and response body
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            exchange.getResponse().getHeaders().add("Content-Type", "application/json");
            return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory()
                    .wrap(errorMessage.getBytes())));
        }
    }
    
    1. Register the entrypoint
    @Configuration
    @EnableWebFluxSecurity
    public class SecurityConfig {
    
        private final CustomAuthenticationEntryPoint authenticationEntryPoint;
    
        @Autowired
        public SecurityConfig(CustomAuthenticationEntryPoint authenticationEntryPoint) {
            this.authenticationEntryPoint = authenticationEntryPoint;
        }
    
        @Bean
        public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
            return http
                    .exceptionHandling(t -> t.authenticationEntryPoint(authenticationEntryPoint))
                    // Configure other security rules
                    .build();
        }
    }