Reputation: 28305
I've seen many questions requesting how to handle security scenarios, all either have solutions for method annotations (i.e. @PreAuthorize("hasRole('ROLE_USER')")
) or using a point-cut.
However what if the resource isn't known if the user has access until the resource has been read from a data store? Let's consider a user who has access to a set of customers, the rest endpoint for these customers can be found at /customers/{id}
. A user is only allowed access if they have been granted access to read the account, likewise they must also have access to make a POST
to the same endpoint.
One way would be:
@RequestMapping(value = "/customers/{id}", method = RequestMethod.GET)
public ModelAndView customerPage(String id, HttpServletRequest req, Principal principal) {
if (!req.isUserInRole("ROLE_ADMIN") && !cs.accessGranted(id, principal.getName())) {
throw new AccessDeniedException("You do not have access to view this custoemr.");
}
Customer cust = cs.getCustomer(id);
if (cust == null) {
throw new ResourceNotFoundException("Customer does not exist!");
}
ModelAndView mov = new ModelAndView("customers/info");
mov.addObject("customer", cust);
return mov;
}
I'm wondering if this is the right approach though.
UPDATE: Call to accessGranted
was meant to have id
as an argument which I missed.
Upvotes: 1
Views: 189
Reputation: 7817
There is a way to continue use @PreAuthorize
annotations. You can call beans directly from SpEL expression:
@PreAuthorize("hasRole('ROLE_USER') and [email protected](#principal.getName())")
public ModelAndView customerPage(String id, HttpServletRequest req, Principal principal) {
@cs
refers to bean id = "cs" declared somwhere in your application context. Later you can future simplify it by removing Principal principal
method parameter and getting username directly in SpEL.
If your find yourself using this tehnique often then check out Spring Security ACL module.
Upvotes: 1
Reputation: 8154
My favorite way is to use the @Secured annotation on a method, which takes an array of Strings representing the Role(s) required to execute the method. I like this method because you are not limited to putting security only on URL patterns. For instance, you can add this to a method in your Service class, and any Controller using that Service is now secured.
The other common method is to include URL filters in the Spring Security XML file. I forget the exact syntax, but you basically setup filters that match a URL and indicate what Role(s) are needed.
Upvotes: 0