VietMX's Blog
  • C++
  • JAVA
  • JS
  • NODEJS
  • PYTHON
  • TOOLS
  • BLOCKCHAIN
  • AI
  • EBOOK
  • ACM
  • ALGORITHM
  • Q&A

Redirect to Different Pages after Login with Spring Security

2021 VietMX JAVA 0

Table of Contents

  • 1. Overview
  • 2. The Spring Security Configuration
    • 2.1. Basic Configuration
    • 2.2. Adding the Custom Success Handler
    • 2.3. XML Configuration
  • 3. The Custom Authentication Success Handler
  • 4. Conclusion

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.

2.1. Basic Configuration

Let’s first configure a basic @Configuration and @Service class:

@Configuration
@EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            // ... endpoints
            .formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/login")
                .defaultSuccessUrl("/homepage.html", true)
            // ... other configuration       
    }
}

The part of this configuration to focus on is the defaultSuccessUrl() method. After a successful login, any user will be redirected to homepage.html.

Furthermore, we need to configure users and their roles. For the purpose of this article, we’ll implement a simple UserDetailService with two users, each having one single role. For more on this topic, read our article Spring Security – Roles and Privileges.

@Service
public class MyUserDetailsService implements UserDetailsService {

    private Map<String, User> roles = new HashMap<>();

    @PostConstruct
    public void init() {
        roles.put("admin2", new User("admin", "{noop}admin1", getAuthority("ROLE_ADMIN")));
        roles.put("user2", new User("user", "{noop}user1", getAuthority("ROLE_USER")));
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
        return roles.get(username);
    }

    private List<GrantedAuthority> getAuthority(String role) {
        return Collections.singletonList(new SimpleGrantedAuthority(role));
    }
}

Also note that in this simple example, we won’t use a password encoder, therefore the passwords are prefixed with {noop}.

2.2. Adding the Custom Success Handler

We now have two users with the two different roles: user and admin. After a successful login, both will be redirected to hompeage.html. Let’s look at how we can have a different redirect based on the user’s role.

First, we need to define a custom success handler as a bean:

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

And then replace the defaultSuccessUrl call with the successHandler method, which accepts our custom success handler as a parameter:

@Override
protected void configure(final HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        // endpoints
        .formLogin()
            .loginPage("/login.html")
            .loginProcessingUrl("/login")
            .successHandler(myAuthenticationSuccessHandler())
        // other configuration      
}

2.3. XML Configuration

Before looking at the implementation of our custom success handler, let’s also look at the equivalent XML configuration:

<http use-expressions="true" >
    <!-- other configuration -->
    <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="com.maixuanviet.security.MySimpleUrlAuthenticationSuccessHandler" />

<authentication-manager>
    <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. 

First of all, we need to override the onAuthenticationSuccess method:

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);
    }

Our customized method calls two helper methods:

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);
}

Where the following method does the actual work and maps the user to the target URL:

protected String determineTargetUrl(final Authentication authentication) {

    Map<String, String> roleTargetUrlMap = new HashMap<>();
    roleTargetUrlMap.put("ROLE_USER", "/homepage.html");
    roleTargetUrlMap.put("ROLE_ADMIN", "/console.html");

    final Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
    for (final GrantedAuthority grantedAuthority : authorities) {
        String authorityName = grantedAuthority.getAuthority();
        if(roleTargetUrlMap.containsKey(authorityName)) {
            return roleTargetUrlMap.get(authorityName);
        }
    }

    throw new IllegalStateException();
}

Note that this method will return the mapped URL for the first role the user has. So if a user has multiple roles, the mapped URL will be the one that matches the first role given in the authorities collection.

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

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.

Related posts:

Introduction to Using Thymeleaf in Spring
Spring MVC and the @ModelAttribute Annotation
Spring Autowiring of Generic Types
Spring Cloud Series – The Gateway Pattern
Java Program to Check whether Graph is a Bipartite using BFS
Java Program to Compute Discrete Fourier Transform Using the Fast Fourier Transform Approach
Logout in an OAuth Secured Application
The Modulo Operator in Java
Java Program to Find Nearest Neighbor for Dynamic Data Set
Guide to System.gc()
Java Program to Find the Edge Connectivity of a Graph
Send email with JavaMail
Java Program to add two large numbers using Linked List
Assert an Exception is Thrown in JUnit 4 and 5
Introduction to the Java ArrayDeque
Java Program to Perform Postorder Non-Recursive Traversal of a Given Binary Tree
Giới thiệu Google Guice – Injection, Scope
Uploading MultipartFile with Spring RestTemplate
Spring Data JPA and Null Parameters
Handle EML file with JavaMail
Java Program to Implement Sorted Circularly Singly Linked List
The Spring @Controller and @RestController Annotations
Hướng dẫn Java Design Pattern – Dependency Injection
Tránh lỗi NullPointerException trong Java như thế nào?
Guide to the Java Clock Class
Mệnh đề if-else trong java
Serverless Functions with Spring Cloud Function
Java Program to Implement Skip List
String Joiner trong Java 8
Java Program to Implement Max Heap
So sánh HashSet, LinkedHashSet và TreeSet trong Java
A Quick Guide to Spring MVC Matrix Variables
  • Different Pages
  • Login
  • Redirect
  • Spring Security

SEARCH

  • The Stern-Brocot tree and Farey sequences

    2021 0
  • 15 Puzzle Game: Existence Of The Solution

    2021 0
  • Josephus Problem

    2021 0
  • Optimal schedule of jobs given their deadlines and durations

    2021 0
  • Scheduling jobs on two machines

    2021 0
  • Scheduling jobs on one machine

    2021 0
  • Sprague-Grundy theorem

    2021 0
  • Games on arbitrary graphs

    2021 0
  • K-th order statistic in O(N)

    2021 0
  • Search the subarray with the maximum/minimum sum

    2021 0
  • Longest increasing subsequence

    2021 0
  • Range Minimum Query

    2021 0
  • Heavy-light decomposition

    2021 0
  • 2 – SAT

    2021 0
  • Paint the edges of the tree

    2021 1
  • Edge connectivity / Vertex connectivity

    2021 0
  • Topological Sorting

    2021 0
  • Kuhn’s Algorithm for Maximum Bipartite Matching

    2021 0

Algorithm Array Collections Convert Converting Custom Data Structure Deep Learning Dictionary File Finding Generate Graph Guide HttpClient Implement InputStream Introduction Jackson Java JavaScript JPA JUnit List Machine Learning MongoDB New Year Node.js OAuth2 Perform Program Python REST API Set Spring Spring Boot Spring Cloud Spring Data Spring MVC Spring Security Stream String Strings Tree WebFlux

  • ACM
  • AI
  • ALGORITHM
  • BLOCKCHAIN
  • C/C++
  • EBOOK
  • JAVA
  • JS
  • NODEJS
  • PYTHON
  • TOOLS
CONTACT INFORMATION
  • Email: maixuanviet.com@gmail.com
  • Skype: maixuanviet.com@outlook.com
  • Linkein: linkedin.com/in/maixuanviet
  • HackerRank: hackerrank.com/vietmx
  • Github: github.com/vietmx
  • Tiktok: tiktok.com/@maixuanviet.com

DMCA.com Protection Status