I need to post process the response of any Micronaut controller and eliminate items in the response body when a user is not authorized to access them.
In a blocking world I would implement it like
protected MutableHttpResponse<?> doFilterOnce(HttpRequest<?> request, ServerFilterChain chain) {
// If Micronaut Security rejected the request simpy do nothing
if (request.getAttribute(SecurityFilter.REJECTION).isPresent()) {
log.debug("Request was previously rejected. Not going to contact PDP");
return chain.proceed(request);
}
HttpMethod method = request.getMethod();
if (method.equals(GET) || method.equals(HEAD)) {
MutableHttpResponse<?> response = chain.proceed(request);
if (response.getBody().isPresent()) {
// iterate through the body
Object theBody = response.getBody().get();
if (theBody instanceof Collection) {
Collection<?> iterable = (Iterable<?>) theBody;
// select all elements that are rejected. This is a blocking call.
List<?> collect = iterable.stream().filter(item -> mySecService.isAllowed(item) == false).collect(Collectors.toList());
// remove them
iterable.removeAll(collect);
// reset the body
response.body(iterable);
}
}
} else {
return chain.proceed(request)
}
return response;
}
Micronaut states that
Filters execute in the event loop therefore blocking operations must be offloaded to another thread pool.
and therefore in the real world it requires mit to return
- a Flowable
- implement the code above in a reactive way
This is what I have done so far.
if (method.equals(GET) || method.equals(HEAD)) {
// post process
return Flowable.fromPublisher(chain.proceed(request))
.doNext(response -> {
Optional<?> body = response.getBody();
if (body.isPresent()) {
// how can I continue here an process the response body collection?
}
});
}
Can someone give me a hint how to continue processing the response body, do the security check, remove the items and reset the new body?