Reputation: 254
I have a problem with populating a model content in Spring MVC application, based on user role managed by Spring Security.
In my application (simplified example) I've got two roles defined: ROLE_USER and ROLE_ADMIN. Also I've got a page that displays a two separate lists of objects: readers (only available for ADMIN) and books (for both, ADMIN and USER).
There is no problem in conditional displaying lists in JSP Page, but I need to prepare model first and I don't want to load readers list if current user isn't an ADMIN.
I've thought about using Spring EL in Java code to determine if user has specified role (hasRole('ROLE_ADMIN')), but I can't find a way to manually evaluate that code.
Is there some way to call Spring EL handler in controller source code, or maybe there is a better solution (on architectural or design pattern level) for conditionally populating model, than checking roles directly in java code.
Upvotes: 1
Views: 3149
Reputation: 254
If conditionally displaying of page parts is controlled by JSP page, then a conditional populating of model should be done by a controller (because JSP page and Controller are tightly coupled in view layer). If we use annotations in service layer it will put the responsibility in wrong layer of an application (in service layer instead of view layer).
My final solution is based on remembering a Set of user Roles as user session attribute:
/* This is executed once, after user successful login. */
Set<String> roles = new HashSet<String>();
for (GrantedAuthority authority : authentication.getAuthorities()) {
roles.add(authority.getAuthority());
}
session.setAttribute("userRoles", roles);
Then if I want to conditionally populate a model I only need to check if required Role is contained by that Set.
Set<String> roles = (Set<String>) session.getAttribute("userRoles");
if(roles.contains("ROLE_ADMIN")) {
putReadersInModel(model);
}
I think that solution is clean and keeps the responsibility of proper populating of model in Controller.
Upvotes: 0
Reputation: 7522
The issue was tackled by @Chepech and @Boris Kirzner in Prevent Method call without Exception using @PreAuthorize Annotation. That way you can return null (or empty list in your case) when a AccessDeniedException occurs.
Upvotes: 1
Reputation: 2155
One approach would be to just return everything when you're generating your model then rely on @PostFilter
to filter that result based on roles. If you don't want to go that route, you could have your controller call out to another bean to build up specific parts of your model, and that other bean could have the role annotations attached. That would effectively limit you from ever creating objects if they won't be used.
Upvotes: 0