Spring Boot authorisation in services

andkov :

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.

Marco Behler :

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
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=295495&siteId=1