
Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:
Once the early-adopter seats are all used, the price will go up and stay at $33/year.
Last updated: January 8, 2024
In this quick tutorial, we’re going to illustrate how to customize Spring Security’s authentication failures handling in a Spring Boot application. The goal is to authenticate users using a form login approach.
For an introduction to Spring Security and Form Login in Spring Boot, please refer to this and this article, respectively.
Authentication and Authorization are often used in conjunction because they play an essential, and equally important, role when it comes to granting access to the system.
However, they have different meanings and apply different constraints when validating a request:
We can customize both authentication and authorization failures handling, however, in this application, we’re going to focus on authentication failures.
Spring Security provides a component that handles authentication failures for us by default.
However, it’s not uncommon to find ourselves in a scenario where the default behavior isn’t enough to meet requirements.
If that is the case, we can create our own component and provide the custom behavior we want by implementing the AuthenticationFailureHandler interface:
public class CustomAuthenticationFailureHandler
implements AuthenticationFailureHandler {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public void onAuthenticationFailure(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException exception)
throws IOException, ServletException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
Map<String, Object> data = new HashMap<>();
data.put(
"timestamp",
Calendar.getInstance().getTime());
data.put(
"exception",
exception.getMessage());
response.getOutputStream()
.println(objectMapper.writeValueAsString(data));
}
}
By default, Spring redirects the user back to the login page with a request parameter containing information about the error.
In this application, we’ll return a 401 response that contains information about the error, as well as the timestamp of its occurrence.
Besides the default component, Spring has others ready to use components that we can leverage depending on what we want to do:
Now that we have created our custom AuthenticationFailureHandler, let’s configure our application and override Spring’s default handler:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user1 = User.withUsername("user1")
.password(passwordEncoder().encode("user1Pass"))
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user1);
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.failureHandler(authenticationFailureHandler())
return http.build();
}
@Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
Note the failureHandler() call – it’s where we can tell Spring to use our custom component instead of using the default one.
In this example, we customized our application’s authentication failure handler leveraging Spring’s AuthenticationFailureHandler interface.
When running locally, you can access and test the application at localhost:8080