Spring Security — Demonstrating Custom Authentication Success Handler

Syed Hasan
2 min readFeb 13, 2020

--

Custom Authentication Success Handler

In our previous post I demonstrated authentication success with defaultSuccessUrl(String s) which works very well. However, if we want to have more control (in many cases we may require it) over our authentication success mechanism, we will have to create a Custom AuthSuccessHandler class, which will implement AuthenticationSuccessHandler interface. Later we will create a bean of our custom AuthSuccessHandler class and use it in replacement of defaultSuccessUrl(String s) in configure(HttpSecurity http) method. The code is demonstrated below.

a) Custom AuthSuccessHandler class

public class AuthSuccessHandler implements AuthenticationSuccessHandler {

@Override
public void onAuthenticationSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
HttpSession session = request.getSession();
User authUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
session.setAttribute("user", authUser);
session.setAttribute("username", authUser.getUsername());
session.setAttribute("authorities", authentication.getAuthorities());


//set our response to OK status
response.setStatus(HttpServletResponse.SC_OK);

//since we have created our custom success handler, its up to us, to where
//we will redirect the user after successfully login
SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
// String requestUrl = savedRequest.getRedirectUrl();
response.sendRedirect(savedRequest.getRedirectUrl().isEmpty() ? "/" : savedRequest.getRedirectUrl()); //requestUrl!=null?requestUrl:
}
}

b) Creating a bean of AuthSuccessHandler

@Bean
public AuthSuccessHandler authSuccessHandler() {
return new AuthSuccessHandler();
}

c) Using AuthSuccessHandler in WebSecurityConfiguration class

....................
// Injecting dependency
private final AuthSuccessHandler authSuccessHandler;

public WebSecurityConfiguration(AuthSuccessHandler authSuccessHandler) {
this.authSuccessHandler = authSuccessHandler;
}
..................http
.formLogin()
.loginPage("/login")
.permitAll()
.usernameParameter("username")
.passwordParameter("password")
.successHandler(authSuccessHandler)
.
failureUrl("/login?error=true")

The full source code of WebSecurityConfiguration is given below.

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter{

private final AuthSuccessHandler authSuccessHandler;

public WebSecurityConfiguration(AuthSuccessHandler authSuccessHandler) {
this.authSuccessHandler = authSuccessHandler;
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("mainul35").password("{noop}secret").roles("ADMIN");
auth.inMemoryAuthentication().withUser("mainul36").password("{noop}secret").roles("USER");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
// We are disabling CSRF so that our forms don't complain for a CSRF token.
// Beware that it can create a security vulnerability
http.csrf().disable();

// We are permitting all static resources to be accessed publicly
http
.authorizeRequests()
.antMatchers("/images/**", "/css/**", "/js/**").permitAll()
// We are restricting endpoints for individual roles.
// Only users with allowed roles will be able to access individual endpoints.
.and()
.authorizeRequests()
.antMatchers("/course/add").hasRole("ADMIN")
.antMatchers("/course/show-all").hasAnyRole("ADMIN", "USER")
.antMatchers("/course/edit").hasAnyRole("USER")
// Following line denotes that all requests must be authenticated.
// Hence, once a request comes to our application, we will check if the user is authenticated or not.
.anyRequest().authenticated()

// Here we are configuring our login form
.and()
.formLogin()
.loginPage("/login") // Login page will be accessed through this endpoint. We will create a controller method for this.
//.loginProcessingUrl("/login-processing") // This endpoint will be mapped internally. This URL will be our Login form post action.
.permitAll() // We re permitting all for login page
.usernameParameter("username")
.passwordParameter("password")
.successHandler(authSuccessHandler)

// .defaultSuccessUrl("/") // If the login is successful, user will be redirected to this URL.
.failureUrl("/login?error=true") // If the user fails to login, application will redirect the user to this endpoint
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/");
}
}

The source code for this project will be found here.

--

--

Syed Hasan
Syed Hasan

Written by Syed Hasan

Software Engineer | Back-End Developer | Spring Developer | Cloud Enthusiast

No responses yet