spring security redirect based on role

19,422

Solution 1

Write a spring controller which will serve different pages to be shown based on user role. Write Authentication success handler class and write code to decide where to redirect based on roles.

First of all <form-login /> tag need to be changed.

<form-login login-page="/landing" authentication-success-handler-ref="authSuccessHandler" />

<beans:bean id="authSuccessHandler" class="com.package.AuthSuccessHandler" />

Remove default-target-url attribute. Let auth handler decide where to redirect the user.

Auth success handler class will be like :

public class AuthSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
    @Override
    protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response) {
        // Get the role of logged in user
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        String role = auth.getAuthorities().toString();

        String targetUrl = "";
        if(role.contains("client")) {
            targetUrl = "/client/index";
        } else if(role.contains("agency")) {
            targetUrl = "/agency/index";
        }
        return targetUrl;
    }
}

This is a sample code. Change it as per your requirements.

Solution 2

You can use annotation based solution by using custom success handler like this:

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

@Component
public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Override
    protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException {
        String targetUrl = determineTargetUrl(authentication);

        if (response.isCommitted()) {
            System.out.println("Can't redirect");
            return;
        }

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

    /*
     * This method extracts the roles of currently logged-in user and returns
     * appropriate URL according to his/her role.
     */
    protected String determineTargetUrl(Authentication authentication) {
        String url = "";

        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

        List<String> roles = new ArrayList<String>();

        for (GrantedAuthority a : authorities) {
            roles.add(a.getAuthority());
        }

        if (isDba(roles)) {
            url = "/db";
        } else if (isAdmin(roles)) {
            url = "/admin";
        } else if (isUser(roles)) {
            url = "/home";
        } else {
            url = "/accessDenied";
        }

        return url;
    }

    private boolean isUser(List<String> roles) {
        if (roles.contains("ROLE_USER")) {
            return true;
        }
        return false;
    }

    private boolean isAdmin(List<String> roles) {
        if (roles.contains("ROLE_ADMIN")) {
            return true;
        }
        return false;
    }

    private boolean isDba(List<String> roles) {
        if (roles.contains("ROLE_DBA")) {
            return true;
        }
        return false;
    }

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

    protected RedirectStrategy getRedirectStrategy() {
        return redirectStrategy;
    }

}

And security config as:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    CustomSuccessHandler customSuccessHandler;

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("USER");
        auth.inMemoryAuthentication().withUser("admin").password("root123").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
        .antMatchers("/", "/home").access("hasRole('USER')")
        .antMatchers("/admin/**").access("hasRole('ADMIN')")
        .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
        .and().formLogin().loginPage("/login").successHandler(customSuccessHandler)
        .usernameParameter("ssoId").passwordParameter("password")
        .and().csrf()
        .and().exceptionHandling().accessDeniedPage("/Access_Denied");
    }

}

Solution 3

It is better to check roles with equals in granted authority, contains may fail if multiple role exist with a same part.

Add authentication success handler in form login config like below:

<http auto-config="true">
    <intercept-url pattern="/Freelancer/**" access="ROLE_FREELANCE" />
    <intercept-url pattern="/Client/**" access="ROLE_CLIENT" />
    <intercept-url pattern="/Agency/**" access="ROLE_AGENCY" />
    <intercept-url pattern="/Manager/**" access="ROLE_MANAGER" />
    <intercept-url pattern="/User/**" access="ROLE_USER" />
    <form-login login-page='/login.html'
                authentication-failure-url="/login.html?error=true"
                authentication-success-handler-ref="myAuthenticationSuccessHandler"/>
    <logout logout-url="/logout" logout-success-url="/" />
</http>

And the success handler goes like this:

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 isFreelance = false;
        boolean isClient = false;
        boolean isAgency = false;
        boolean isManager = false;
        Collection<? extends GrantedAuthority> authorities
                = authentication.getAuthorities();
        for (GrantedAuthority grantedAuthority : authorities) {
            if (grantedAuthority.getAuthority().equals("ROLE_FREELANCE")) {
                isFreelance = true;
                break;
            } else if (grantedAuthority.getAuthority().equals("ROLE_CLIENT")) {
                isClient = true;
                break;
            } else if (grantedAuthority.getAuthority().equals("ROLE_AGENCY")) {
                isAgency = true;
                break;
            } else if (grantedAuthority.getAuthority().equals("ROLE_MANAGER")) {
                isManager = true;
                break;
            } else if (grantedAuthority.getAuthority().equals("ROLE_USER")) {
                isUser = true;
                break;
            }
        }

        if (isFreelance) {
            return "freelance/homepage.html";
        } else if (isClient) {
            return "client/homepage.html";
        } else if (isAgency) {
            return "agency/homepage.html";
        } else if (isManager) {
            return "manager/homepage.html";
        } else if (isUser) {
            return "user/homepage.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;
    }
}
Share:
19,422

Related videos on Youtube

user3321738
Author by

user3321738

Updated on September 15, 2022

Comments

  • user3321738
    user3321738 over 1 year

    i have the following spring-security.xml file :-

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security"
        xmlns:beans="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security-3.0.xsd">
    
        <http auto-config="true">
               <intercept-url pattern="/Freelancer/**" access="ROLE_FREELANCE" />
               <intercept-url pattern="/Client/**" access="ROLE_CLIENT" />
               <intercept-url pattern="/Agency/**" access="ROLE_AGENCY" />
               <intercept-url pattern="/Manager/**" access="ROLE_MANAGER" />
               <intercept-url pattern="/User/**" access="ROLE_USER" />
               <form-login default-target-url="/${role}" login-page="/login.jsp" />
               <logout logout-url="/logout" logout-success-url="/" />
        </http>
    
        <authentication-manager>
               <authentication-provider>
                 <jdbc-user-service data-source-ref="dataSource" 
                   users-by-username-query="select user_name,password, enabled from Users where user_name=?"  
                   authorities-by-username-query="select u.user_name, u.role from Users u where u.user_name =?"/>                 
               </authentication-provider>
        </authentication-manager>
    
    </beans:beans>  
    

    what i want, i want to redirect the user to their workspace, for example if Client login then he will be redirected to the /Client/index.jsp, if Agency login, they will be redirected to the /Agency/index.jsp.

    is there any way to access the role before, he will be redirected to their workspace in spring-security.xml file.

    <form-login default-target-url="/${role}" login-page="/login.jsp" />
    

    I have the directory structure similer to role.

    have any idea.

  • Chaibi Alaa
    Chaibi Alaa over 8 years
    Thats is be on the CustomService.java where we map the roles to spring secuiry ? ?
  • Malinda
    Malinda about 5 years
    here in security config file after .loginPage("/login") you have to add logging processing Url as .loginProcessingUrl("here yout url")