Redirect to Different Pages after Login with Spring Security

1. Overview

A common requirement for a web application is to redirect different types of users to different pages after login. An example of this would be redirecting standard users to a /homepage.html page and admin users to a /console.html page for example.

This article will show how to quickly and safely implement this mechanism using Spring Security. The article is also building on top of the Spring MVC tutorial which deals with setting up the core MVC stuff necessary for the project.

2. The Spring Security Configuration

Spring Security provides a component that has the direct responsibility of deciding what to do after a successful authentication – the AuthenticationSuccessHandler.

Let’s see how we can configure this in a @Configuration class:

@Configuration
@EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean("authenticationManager")
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // @formatter:off
        auth.inMemoryAuthentication()
            .withUser("user1").password("{noop}user1Pass").roles("USER")
            .and()
            .withUser("admin1").password("{noop}admin1Pass").roles("ADMIN");
        // @formatter:on
    }

    @Bean
    public AuthenticationSuccessHandler myAuthenticationSuccessHandler(){
        return new MySimpleUrlAuthenticationSuccessHandler();
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/anonymous*").anonymous()
            .antMatchers("/login*").permitAll()
            .anyRequest().authenticated()

            .and()
            .formLogin()
            .loginPage("/login.html")
            .loginProcessingUrl("/login")
            .successHandler(myAuthenticationSuccessHandler())
            // ...
    }
}

The parts of this configuration to focus on are the definition of the custom authentication success handler bean and using the successHandler() method to add the bean to the security configuration.

The rest of the configuration is pretty standard stuff: a single, simple http element securing everything and only permitting unauthenticated access to /login*, and the standard in-memory authentication provider to keep things simple.

And the equivalent xml configuration:

<http use-expressions="true" >
    <intercept-url pattern="/login*" access="permitAll" />
    <intercept-url pattern="/**" access="isAuthenticated()" />

    <form-login login-page='/login.html'
      authentication-failure-url="/login.html?error=true"
      authentication-success-handler-ref="myAuthenticationSuccessHandler"/>
    <logout/>
</http>

<beans:bean id="myAuthenticationSuccessHandler"
  class="org.baeldung.security.MySimpleUrlAuthenticationSuccessHandler" />

<authentication-manager id="authenticationManager">
    <authentication-provider>
        <user-service>
            <user name="user1" password="{noop}user1Pass" authorities="ROLE_USER" />
            <user name="admin1" password="{noop}admin1Pass" authorities="ROLE_ADMIN" />
        </user-service>
    </authentication-provider>
</authentication-manager>

3. The Custom Authentication Success Handler

Besides the AuthenticationSuccessHandler interface, Spring also provides a sensible default for this strategy component – the AbstractAuthenticationTargetUrlRequestHandler and a simple implementation – the SimpleUrlAuthenticationSuccessHandler. Typically these implementations will determine the URL after login and perform a redirect to that URL.

While somewhat flexible, the mechanism to determine this target URL does not allow the determination to be done programmatically – so we’re going to implement the interface and provide a custom implementation of the success handler. This implementation is going to determine the URL to redirect the user to after login based on the role of the user:

public class MySimpleUrlAuthenticationSuccessHandler
  implements AuthenticationSuccessHandler {

    protected Log logger = LogFactory.getLog(this.getClass());

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
      HttpServletResponse response, Authentication authentication)
      throws IOException {

        handle(request, response, authentication);
        clearAuthenticationAttributes(request);
    }

    protected void handle(HttpServletRequest request,
      HttpServletResponse response, Authentication authentication)
      throws IOException {

        String targetUrl = determineTargetUrl(authentication);

        if (response.isCommitted()) {
            logger.debug(
              "Response has already been committed. Unable to redirect to "
              + targetUrl);
            return;
        }

        redirectStrategy.sendRedirect(request, response, targetUrl);
    }

    protected String determineTargetUrl(Authentication authentication) {
        boolean isUser = false;
        boolean isAdmin = false;
        Collection<? extends GrantedAuthority> authorities
         = authentication.getAuthorities();
        for (GrantedAuthority grantedAuthority : authorities) {
            if (grantedAuthority.getAuthority().equals("ROLE_USER")) {
                isUser = true;
                break;
            } else if (grantedAuthority.getAuthority().equals("ROLE_ADMIN")) {
                isAdmin = true;
                break;
            }
        }

        if (isUser) {
            return "/homepage.html";
        } else if (isAdmin) {
            return "/console.html";
        } else {
            throw new IllegalStateException();
        }
    }

    protected void clearAuthenticationAttributes(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return;
        }
        session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
    }

    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
        this.redirectStrategy = redirectStrategy;
    }
    protected RedirectStrategy getRedirectStrategy() {
        return redirectStrategy;
    }
}

The determineTargetUrl – which is the core of the strategy – simply looks at the type of user (determined by the authority) and picks the target URL based on this role.

So, an admin user – determined by the ROLE_ADMIN authority – will be redirected to the console page after login, while the standard user – as determined by ROLE_USER – will be redirected to the homepage.

4. Conclusion

As always, the code presented in this article is available over on Github. This is a Maven based project, so it should be easy to import and run as it is.

Leave a Reply

Your email address will not be published.