Reputation: 98
I have a Spring Boot application which uses Spring Security to Authenticate and Authorise requests using a JWT. However, some requests should only be able to be executed by a particular user. For example:
GET /users/{id}/orders
should only return the list of orders if {id}
is the current user or the current user is ADMIN
PUT /orders/{id}
should only edit the order if the its payer
is the current user
PUT /representation-requests/{id}/accept
should only work if the current user is the target
of the representation request
Because of the usage of JWTs, the way I get the current user's ID is by
String userId = ((DecodedJWT) SecurityContextHolder.getContext().getAuthentication().getDetails()).getSubject();
I've implemented this in the various methods of the services responsible for handling each API call. My question is if there is a more general way to do this using Spring Boot and Spring Security? Or is this not a standard use case?
I have looked at @PreAuthorize
annotation in controllers, but it does not suite my needs as the URL parameters are not enough to check the nested entities. @PostAuthorize
in controllers seems closer, but because of the JWT I couldn't get it to work (and it also seems a bit clunky to do long code in annotations, not sure it is better than doing it in the service itself). I appreciate a pointer in the right direction.
Upvotes: 1
Views: 369
Reputation: 3724
You'll have to play around with it a bit (I can't give you 100% specifics for JWT), but you basically could use SpEL to achieve what you want. (I'm unsure why you think @PostAuthorize could be a better fit, though)
Either like so, for simple checks (# denotes a method parameter)
@PreAuthorize("principal?.id == #id")
public List<Order> ordersForUsers(Integer id) {
// do someting
}
Or like so, delegating to a custom bean (@ denotes a bean name, hash the method param, 'admin' the role you want, or any other parameter, really)
@PreAuthorize("@yourBean.hasPermission(principal, #id, 'admin')")
public List<Order> ordersForUsers(Integer id) {
// do someting
}
Upvotes: 2