0

With @RequestMapping, request can be associated with different controller functions through header or request parameters. Is there a way to achieve this base on the user user role? The aim is avoid if statement in the controller.

ltfishie
  • 2,917
  • 6
  • 41
  • 68
  • See accepted answer (plus various other suggestions) here: http://stackoverflow.com/questions/17995744/spring-security-mvc-same-requestmapping-different-secured – Alan Hay Dec 02 '14 at 18:04

2 Answers2

1

As far as I am aware, there is not anything that comes out of the box, but if you wanted to you could probably create a custom mapping annotation to do this routing for you.

I have not actually tried any of this code, but something like:

Your new annoation, used like @UserRoleMapping("ROLE_ADMIN")

@Target( ElementType.TYPE )
@Retention(RetentionPolicy.RUNTIME)
public @interface UserRoleMapping {
    String[] value();
}

Next, you can just extend the standard Spring RequestMappingHandlerMapping class (this is the class that handles the standard mapping of @RequestMapping annotations). You just need to tell the mapping handler to also take into account a custom condition:

public class UserRoleRequestCondition extends RequestMappingHandlerMapping {
    @Override protected RequestCondition<?> getCustomTypeCondition(Class<?> handlerType) {
        UserRoleMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, UserRoleMapping.class);
        return (typeAnnotation != null) ? new UserRoleRequestCondition( typeAnnotation.value() ) : null;
    }
}

The above code just checks the controller for your new annotation created above and if it is found it returns a new condition class, constructed with the value you have set in the annotation (e.g. "ROLE_ADMIN"). This MappingHandler will need to be set in your Spring config (whereever you are currently setting the RequestMappingHandlerMapping, just replace it with one of these).

Next we need to create the custom condition - this is the guy that is going to be invoked on request to determine if a request matches the controller:

public class UserRoleRequestCondition implements RequestCondition<UserRoleRequestCondition> {
    private final Set<String> roles;

    public UserRoleRequestCondition( String... roles ) {
        this( Arrays.asList(roles) );
    }

    public UserRoleRequestCondition( Collection<String> roles ) {
        this.roles = Collections.unmodifiableSet(new HashSet<String>(roles));
    }

    @Override public UserRoleRequestCondition combine(UserRoleRequestCondition other) {
        Set<String> allRoles = new LinkedHashSet<String>(this.roles);
        allRoles.addAll(other.roles);
        return new UserRoleRequestCondition(allRoles);
    }

    @Override public UserRoleRequestCondition getMatchingCondition( HttpServletRequest request ) {
        UserRoleRequestCondition condition = null;
        for (String r : roles){
            if ( request.isUserInRole( r ) ){
                condition = this;
            }
        }
        return condition;
    }

    @Override public int compareTo(UserRoleRequestCondition other, HttpServletRequest request) {
        return (other.roles - this.roles).size();
    }
}

In the above, the method getMatchingCondition is where we match the request. (apologies if I have missed some semi-colons or return keywords etc - this is based on groovy, but hopefully if you are in java you can work out where those bits go!)

Props to Marek for his more detailed answer on the more fully-formed solution to custom routing based on the subdomain that I used when I had to implement something similar! How to implement @RequestMapping custom properties - That gives more details about what is going on, and how to have method level annotations (this example skips that and only defines class level annotations)

I have also written up some notes on this here: http://automateddeveloper.blogspot.co.uk/2014/12/spring-mvc-custom-routing-conditions.html

Community
  • 1
  • 1
rhinds
  • 9,976
  • 13
  • 68
  • 111
0

Implement AuthenticationSuccessHandler onAuthenticationSuccess redirect to specific controller based on the User Role.

Ramesh Kotha
  • 8,266
  • 17
  • 66
  • 90
  • Thanks while this would work for a single url after login, I am looking for a general solution that could be applied to any controller like @RequestMapping (params="a=b") – ltfishie Dec 02 '14 at 17:24