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.