Sebb77
Sebb77

Reputation: 2481

Spring MVC controller inheritance with spring security

I'm trying to create a generic controller using spring mvc 3.2.3 and spring security 3.1.3. What i'm trying to achieve is something like this:

public abstract class DataController<E extends PersistentEntity> {
protected abstract E getEntity(String id);

@RequestMapping(value="/view/{id}", method=RequestMethod.GET)
public String view(@PathVariable("id") String id, ModelMap map) {
      E ent = getEntity(id);
      map.put("entity", entity);
      return "showEntity";
    }
}

My extended class will have a specific controller mapping in the class name so that i can access the url by using the controller name:

@Controller
@RequestMapping("/company**")
@Secured("ROLE_ADMIN")
public class CompaniesController extends DataController<Company> {
    @Autowired
    private AppService appService;

    @Override
    protected Company getEntity(String id) {
        return appService.getCompany(id);
    }
}

My problem is that the url /company/view is not secured by ROLE_ADMIN and can be accessed by anyone, (i think) because the /view is not defined in the controller where the @Secured is being used.

This can be fixed by just overriding the view method and define the mapping in my company class:

    . . .

    @Override
    @RequestMapping(value = "/view/{id}", method = RequestMethod.GET)
    public String view(String id, ModelMap map) {
        return super.view(id, map);
    }

    . . .

In this case the security works correctly, but i want to know if there is another method. Since i have a lot of methods in my abstract class, this will create a problem and a mess to override all methods just to call the super.

Is there a way to fix this issue?

thanks all for the help :)

Upvotes: 3

Views: 2534

Answers (1)

ced-b
ced-b

Reputation: 4065

I know it's a year later, but I had the same problem and figured out a possible solution for this. It is not 100% annotation based, but works and is somewhat elegant

The abstract superclass:

@PreAuthorize("hasAnyRole(this.roles)")
public abstract class DataController<E extends PersistentEntity> 
{
    protected abstract E getEntity(String id);

    protected abstract String[] getRoles();

    @RequestMapping(value="/view/{id}", method=RequestMethod.GET)
    public String view(@PathVariable("id") String id, ModelMap map) {
       E ent = getEntity(id);
       map.put("entity", entity);
       return "showEntity";
    }
 }

On the subclass you simply implement getRoles() to return an array of roles that are required to access this class.

@PreAuthorize is another way to check authentication, that allows you to use SpEL expression. this.roles refers to he getRoles() property on the annotated object.

Upvotes: 8

Related Questions