I am using spring boot, and I have enabled the global method security in WebSecurityConfigurerAdapter by
@EnableGlobalMethodSecurity(prePostEnabled = true, order = Ordered.HIGHEST_PRECEDENCE)
And Below is my controller code
@PreAuthorize("hasAnyRole('admin') or principal.id == id")
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public User updateUser(@PathVariable("id") String id, @Valid @RequestBody UserDto userDto)
{ ....}
However, when a non-admin user try to do a PUT request, the JSR303 validator will kick in before @PreAuthorize. For example, non-admin user ended up getting something like "first name is required" instead of "access denied". But after user supplied the first name variable to pass the validator, access denied was returned.
Does anyone know how to enforce the @PreAuthorize get checked before @Valid or @Validated?
And I have to use this kind of method-level authorization instead of url-based authorization in order to perform some complex rule checking.
The @Valid annotation ensures the validation of the whole object. Importantly, it performs the validation of the whole object graph. However, this creates issues for scenarios needing only partial validation. On the other hand, we can use @Validated for group validation, including the above partial validation.
The @PreAuthorize annotation checks the given expression before entering the method, whereas the @PostAuthorize annotation verifies it after the execution of the method and could alter the result.
Access Control using @PreAuthorize and @PostAuthorize The most obviously useful annotation is @PreAuthorize which decides whether a method can actually be invoked or not. For example (from the “Contacts” sample application) @PreAuthorize("hasRole('ROLE_USER')") public void create(Contact contact);
Spring Security provides method level security using @PreAuthorize and @PostAuthorize annotations. This is expression-based access control. The @PreAuthorize can check for authorization before entering into method. The @PreAuthorize authorizes on the basis of role or the argument which is passed to the method.
I had the same issue and I found this post. The comment of M. Deinum helps me to understand what was going wrong
Here is what I did :
Example :
@RequestMapping(method = RequestMethod.POST)
@PreAuthorize("hasRole('MY_ROLE')")
public ResponseEntity createNewMessage(@RequestBody CreateMessageDTO createMessageDTO) {
// The user is authorized
return createNewMessageWithValidation(createMessageDTO);
}
private ResponseEntity createNewMessageWithValidation(@Valid CreateMessageDTO createMessageDTO) {
// The DTO is valid
return ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With