In this Spring Security post, I would like to share with you some code examples that intervene the authentication process of Spring Security in order to run custom logics upon successful login, in a Spring Boot application.

For examples, the application needs to perform these tasks upon user’s successful login:

  • Log user’s information (for auditing purpose)
  • Request to change password if expired, or request to update user’s details
  • Clear previous failed login attempts (for limit login attempts functionality)
  • Clear One-Time Password (for OTP functionality)
  • any custom logics you want to execute after successful authentication
And Spring Security allows programmers to do that by configuring an authentication success hander, which is explained in the following diagram:

spring security login success handler

In this article, I will share with you two different ways for implementing an authentication success handler in a Spring Boot application: simple and advanced.

 

1. Simple Authentication Success Handler

In this way, we create an anonymous class of type AuthenticationSuccessHandler as parameter for the successHandler() method of a FormLoginConfigurer class in a Spring security configuration class, as below:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	...
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
			...
			.formLogin()
				.loginPage("/login")
				.usernameParameter("email")
				.permitAll()
				.successHandler(new AuthenticationSuccessHandler() {

					@Override
					public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
							Authentication authentication) throws IOException, ServletException {
						// run custom logics upon successful login
					}
				})
			...
	}

}
The callback method onAuthenticationSuccess() will be invoked by Spring Security right after a user has logged in successfully to the application.

This approach is suitable for simple use case, e.g. logging information. For example:

.formLogin()
	.loginPage("/login")
	.usernameParameter("email")
	.permitAll()
	.successHandler(new AuthenticationSuccessHandler() {
		
		@Override
		public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
				Authentication authentication) throws IOException, ServletException {
			// run custom logics upon successful login
			
			UserDetails userDetails = (UserDetails) authentication.getPrincipal();
			String username = userDetails.getUsername();
			
			System.out.println("The user " + username + " has logged in.");
			
			response.sendRedirect(request.getContextPath());
		}
	})


As you can see, the code snippet in the callback method prints username of the authenticated user and redirect the user to the homepage.

It’s recommended to extend the SavedRequestAwareAuthenticationSuccessHandler class which will automatically redirect the user to the secured page prior to login. For example:

successHandler(new SavedRequestAwareAuthenticationSuccessHandler() {
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {
		// run custom logics upon successful login
		UserDetails userDetails = (UserDetails) authentication.getPrincipal();
		String username = userDetails.getUsername();
		System.out.println("The user " + username + " has logged in.");
		
		super.onAuthenticationSuccess(request, response, authentication);
	}						
})
It’s better to use this implementation because Spring Security saved the URL prior to login and redirect the user back to that URL upon successful authentication.

 

2. Advanced Authentication Success Handler

In case the authentication success handler class needs to use another business class (a dependency) to perform the custom logics, we need to configure spring security differently.

First, create a separate handler class that extends SavedRequestAwareAuthenticationSuccessHandler class as follows:

@Component
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

	@Autowired
	private CustomerServices customerService;
	
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
			Authentication authentication) throws IOException, ServletException {

		CustomerUserDetails customerDetails = (CustomerUserDetails) authentication.getPrincipal();
		Customer customer = customerDetails.getCustomer();
		
		if (customer.isOTPRequired()) {
			customerService.clearOTP(customer);
		}
		
		super.onAuthenticationSuccess(request, response, authentication);
	}

}
Here, the @Component annotation is used so its instances will be managed by Spring framework and injectable into other components if needed. And as you can see, this handler depends on CustomerService class to perform the custom logics in the callback method onAuthenticationSuccess().

And in the Spring Security configuration class, we need to autowire an instance of the handler class as follows:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	...
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
				.formLogin()
					.loginPage("/login")
					.usernameParameter("email")
					.permitAll()
					.successHandler(loginSuccessHandler)
		...
	}

	@Autowired
	private LoginSuccessHandler loginSuccessHandler;

}
So this advanced configuration would be suitable for almost any use cases of an authentication success handler.

To see the coding in action, I recommend you to watch the following video:

I hope you’ve found this post helpful. To learn more about Spring Security, check the following articles:

 

Related Spring Security Tutorials:

 

Other Spring Boot Tutorials:

 


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Add comment