0

I am new to struts and spring security. Can anyone help me to figure out how to redirect to different urls different users with different roles ? In other words, how to provide determine target url based on user role in struts2 using action controller?

I found the following question determine target url based on roles in spring security 3.1 , but I cannot figure out how to configure the action.

I tried the following setup, but it does not work:

security.xml

 <form-login login-page="/login" authentication-failure-url="/login?error=true" login-processing-url="/j_security_check" default-target-url="/default"/>

struts.xml

<action name="default" class="com.moblab.webapp.action.RoleRedirectAction" method="defaultAfterLogin"/>

RoleRedirectAction.java

package com.moblab.webapp.action;
import javax.servlet.http.HttpServletRequest;
public class RoleRedirectAction extends BaseAction{

public String defaultAfterLogin(HttpServletRequest request) {
    if (request.isUserInRole("ROLE_ADMIN")) {
        return "redirect:/<url>";
    }
    return "redirect:/<url>";
}
}

Thanks a lot.

EDIT 1 I also tried the following annotation

 @Action(value="/default",results={@Result(name="success",location="/querySessions")})

EDIT 2 My final solution looks like the following. I am not sure if it is the best approach, but it works:

public class StartPageRouter extends SimpleUrlAuthenticationSuccessHandler {


@Autowired
private UserService userService;

protected final Logger logger = Logger.getLogger(this.getClass());
private RequestCache requestCache = new HttpSessionRequestCache();

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


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

    //default path for ROLE_USER
    String redirectPath = <url>;

    if (authorities != null && !authorities.isEmpty()) {

        Set<String> roles = getUserRoles(authorities);

        if (roles.contains("ROLE_ADMIN"))
            redirectPath = <url>;
        else if (roles.contains("ROLE_INSTRUCTOR"))
            redirectPath = <url>;
    }

    getRedirectStrategy().sendRedirect(request, response, redirectPath);
}

public void setRequestCache(RequestCache requestCache) {
    this.requestCache = requestCache;
}

private Set<String> getUserRoles(Collection<? extends GrantedAuthority> authorities) {

    Set<String> userRoles = new HashSet<String>();

    for (GrantedAuthority authority : authorities) {
        userRoles.add(authority.getAuthority());
    }
    return userRoles;
}
}

EDIT 3 There are even better solutions here:

http://oajamfibia.wordpress.com/2011/07/07/role-based-login-redirect/#comment-12

Community
  • 1
  • 1
vlr
  • 780
  • 4
  • 16
  • 33

1 Answers1

2

Assuming that you mean that you want to redirect users to different start pages depending on their assigned roles then you can try this. Note that I do all this outside of Struts.

First create your own class that extends Springs SimpleUrlAuthenticationSuccessHandler and override the onAuthenticationSuccess() method. The actual redirect is performed within the onAuthenticationSuccess() method by the line getRedirectStrategy().sendRedirect(request,response,);

So all you need is a means of substituting your own url's.

So, for example I have

package com.blackbox.x.web.security;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;

import com.blackbox.x.entities.UserDTO;
import com.blackbox.x.services.UserService;


public class StartPageRouter extends SimpleUrlAuthenticationSuccessHandler {


 @Autowired
 UserService userService;

 @Autowired
 LoginRouter router;


 protected final Logger logger = Logger.getLogger(this.getClass());
 private RequestCache requestCache = new HttpSessionRequestCache();

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


    requestCache.removeRequest(request, response);

    User user = (User) authentication.getPrincipal();
    UserDTO userDTO = userService.find(user.getUsername());

    getRedirectStrategy().sendRedirect(request, response, router.route(userDTO));
}

public void  setRequestCache(RequestCache requestCache) {
            this.requestCache = requestCache;
        }
}

where LoginRouter is my own class that takes the logged in user and, from the assigned roles determines which URL the user should be directed to.

You then configure Spring Security to use your version using the

authentication-success-handler-ref="customTargetUrlResolver"/> 

and

<beans:bean id="customTargetUrlResolver" class="com.blackbox.x.web.security.StartPageRouter"/>

in your security context xml file.

JKirchartz
  • 17,612
  • 7
  • 60
  • 88
user497087
  • 1,561
  • 3
  • 24
  • 41
  • Thanks. Your response helped a lot. I have several questions though. 1. Why do you need requestCache.removeRequest(request, response); 2. Why request does not have roles and why I cannot use request.isUserInRole() ? Thanks. – vlr Mar 07 '12 at 22:37
  • 1) I'm not sure, but I think it's because Spring caches the original browser request before routing into the login process which it uses to redirect the user after a successful login. So, if a user asks for a secured resource, Spring caches the request, performs the authentication and then redirects the user to the page they originally requested. Since we are forcing the user to a specific page following login, then we don't need the originally requested page - so we're just tidying up. – user497087 Mar 08 '12 at 10:09
  • 2) I don't know, request.isUserInRole() should work. Certainly extending ActionSupport as the base class for your action and using isUserInRole() works for me. – user497087 Mar 08 '12 at 10:16