I'm very new to the Spring Security Framework and I have a little problem here to solve.
I've already managed to use the @PreAuthorized("hasPermission('#person', Permission) annotation for service and controller methods. This works fine for me, but this only works for the whole Domain class.
In my case there are some fields which should be shown to users despite they haven't the permission to read this Person.
A quick example:
This is a very simple example, there are more fields a user could see.
Hopefully you'll understand what I'm asking for.
(I´m sorry my english is not that good.)
EDIT
PersonController
@RequestMapping("/{id}")
public String get(@PathVariable("id") Long personId, Model model,HttpSession session) {
Person person = personService.findById(personId);
/* DO STUFF HERE */
return "person.show";
}
PersonService
@PreAuthorize("hasPermission('#personId', <domainClass>, 'read')")
public Person findById(Long personId) {
return personRepository.findOne(personId);
}
You could do it explicitely by no using @PreAuthorized("hasPermission('#person', Permission)
annotation at all and instead doing it by hand in your code ... but that would partially defect the interest of using Spring Security framework !
I would suggest :
@PreAuthorized("hasPermission('#person', Permission)
annotation in service class layer => it should throw an AccessDeniedException
is user is not allowed to read that profileAccessDeniedException
in the calling controller. As exception will be thrown during the execution of a method of the controller, that handler will be given a chance to process it. Call a non protected method from the relevant service class that will only return public fields and forward to a view indicating You doesn't have the permission to read the profile from Jon DoeIn that configuration, the exception handler should take parameters equivalent to original controller method to have access to :
Principal
executing the requestBut this should not be a problem since an exception handler can accept almost the same parameters that a @RequestMapping
method does in addition to the exception itself.
Per your edit, you get the personId
from a path variable, which would be hard to get from the exception handler. So you should save it as a request attribute before calling the protected service method to get it in the exception handler :
@RequestMapping("/{id}")
public String get(@PathVariable("id") Long personId, Model model,HttpSession session, HttpServletRequest request) {
request.setAttribute("personId", personId);
Person person = personService.findById(personId);
/* DO STUFF HERE */
return "person.show";
}
@ExceptionHandler(AccessDeniedException.class)
public ModelAndView accessDeniedHandler(HttpServletRequest request) {
ModelAndView mav = new ModelAndView("accessDeniedView");
Long personId = request.getAttribute("personId");
// populate your model
return mav;
}