I have a REST controller with a GET method. It returns a resource. I want to verify if the resource belongs to the authorized user by comparing the owner field on the Resource with the authorized user's login. With a normal synchronous request I'd do something like this:
@RestController
@RequestMapping("/api")
public class AController {
private final AService aService;
public AController(AService aService) {
this.aService = aService;
}
@GetMapping("/resources/{id}")
@PostAuthorize("returnObject.ownerLogin == authentication.name")
public Resource getResource(@PathVariable Long id) {
return aService.getResource(id);
}
}
But what if the controller method is asynchronous (implemented with DeferredResult)?
@RestController
@RequestMapping("/api")
public class AController {
private final AService aService;
public AController(AService aService) {
this.aService = aService;
}
@GetMapping("/resources/{id}")
@PostAuthorize("returnObject.ownerLogin == authentication.name")
public DeferredResult<Resource> getResource(@PathVariable Long id) {
DeferredResult<Resource> deferredResult = new DeferredResult<>();
aService
.getResourceAsync(id)
.thenAccept(resource -> {
deferredResult.setResult(resource);
});
return deferredResult;
}
}
Where AService interface looks like this:
@Service
public class AService {
@Async
public CompletableFuture<Resource> getResourceAsync(Long id) {
// implementation...
}
public Resource getResource(Long id) {
// implementation...
}
}
And Resource class is a simple DTO:
public class Resource {
private String ownerLogin;
// other fields, getters, setters
}
In the second example Spring Security obiously looks for the ownerLogin field on the DeferredResult instance. I'd like it to treat the asynchronously resolved Resource as the returnObject in the @PostAuthorize SPEL expression.
Is it possible? Maybe someone can suggest an alternatve approach? Any suggestions are welcome.
Couldn't achieve my goal with
PostAuthorizeand endedd up doing the following:Made
Resourcea subresource of theUserresource. Used aPreAuthorizeannotation to validate user's login.Added an ownership check in
AService. IfResourceowner and the requesting user's login don't match throw an Exception that resolves to a404HTTP status: