I have the following endpoint in my Spring MVC controller:
@RestController
public class ToolsController {
@GetMapping("/v1/auth-check/....id....")
@RolesAllowed(...)
@MyCustomPermissions(...)
public MyResult checkAuth(...., int databaseId, ....) {
Here roles allowed is a standard annotation, which checks with user data and prevent method from being called without permissions.
Now I want additionally to check permissions with the help of a data, which is contained in a database object, identified by parameter databaseId
. Can I read this object from somewhere so that my annotation also prevent method from being called?
I can parse request separately in HandlerInterceptorAdapter#preHandle
This is bad because I will duplicate Spring's work. Are there any other mechanisms?
CodePudding user response:
If the object you're referring to as "database object" is the result returned by checkAuth()
then sure you can examine its contents @PostAuthorize
. If a SpEl expression provided as an argument would not match, then request processing would fail with an exception.
It would look like this:
@PostAuthorize("returnObject.databaseId ... <- your-conditional-logic-here")
Reminder: to make this annotation enabled, prePostEnabled
attribute of the @EnableGlobalMethodSecurity
(which annotates configuration class) needs to be set to true
(I guess you're aware of this, but a random reader might be not):
@EnableGlobalMethodSecurity(prePostEnabled=true)
In case if you didn't refer to the resulting object, then you can retrieve this "database object" right inside the SpEl-expression because we're free to use any Beans and invoke their methods. So it still can be using @PostAuthorize
.
Also, it's worth noticing:
- That it's better keep SpEl-expression as simple as possible, since its hard to test.
HandlerInterceptorAdapter
is deprecated since release version5.3
, so it's not a great alternative.
CodePudding user response:
Use @PreAuthorize
which allows you to define a SpEL to refer to a method in any bean that will be executed before a method is called for permission checking. The permission checking method should return a boolean which true means allow while false means disallow.
In that SpEL , you can use @bean
to refer to a bean and use #foo
or @P
to access the parameters of the method that @PreAuthorize protects.(docs at here)
Something like :
@GetMapping("/v1/auth-check/....id....")
@PreAuthorize("@authzService.isAllow(#databaseId)")
public MyResult checkAuth(...., int databaseId, ....) {
}
which will look for a bean which the name is authzService
and execute its isAllow()
for permission checking.
@Service
public class AuthzService{
public boolean isAllow(int databaseId){
/******************************************
Do the checking here....
Use SecurityContextHolder.getContext().getAuthentication() to access the current user object such that you can check their roles.
******************************************/
}
}