I am writing a service that, for now, will need to implement its own validation of JWT tokens. This will later be handled by a layer before the services.
To do this, I intended to intercept requests using HttpServerFilter
interface:
@Filter(Filter.MATCH_ALL_PATTERN)
public class SecurityFilter implements HttpServerFilter {
private static final Logger LOG = LoggerFactory.getLogger(SecurityFilter.class);
@Override
public Publisher<MutableHttpResponse<?>> doFilter(final HttpRequest<?> request, final ServerFilterChain chain) {
return chain.proceed(request);
}
@Override
public int getOrder() {
return ServerFilterPhase.SECURITY.order();
}
}
The HttpFilter
interface states:
To modify the request filters can either wrap it (using io.micronaut.http.HttpRequestWrapper or pass it along the chain as is
So I try to the wrap the request with this class:
final HttpRequestWrapper<?> wrappedRequest = new HttpRequestWrapper<>(request);
// wrappedRequest.getHeaders() Not mutable
// request.mutate().getHeaders() Mutable
// wrappedRequest.mutate().getHeaders() Mutable
However, both mutate
methods above go to the same default implementation in the HttpRequest
interface:
default MutableHttpRequest<B> mutate() {
throw new UnsupportedOperationException("Request is immutable");
}
The documentation states that the filters support decoration of requests and modification of responses. What is the difference between decorating and modifying here?
The end result I am after is that I want to parse a JWT token, ensure it is valid, and add a field from the token to a new header and retrieve that header from controllers in the following way:
@Get(uri = "/{id}", produces = MediaType.APPLICATION_JSON)
public Optional<Item> findById(@PathVariable("id") final String id, @Header("X-Tenant-Id") final String tenantId) {
return service.findById(id, tenantId);
}
How can I achieve this with Micronaut filters?
It is possible to add attributes, not headers. Attributes fulfill the same purpose in the end.
@Filter(Filter.MATCH_ALL_PATTERN)
public class SecurityFilter implements HttpServerFilter {
public static final String TENANT_ID_ATTRIBUTE_NAME = "tenantId";
private static final Logger LOG = LoggerFactory.getLogger(SecurityFilter.class);
@Override
public Publisher<MutableHttpResponse<?>> doFilter(final HttpRequest<?> request, final ServerFilterChain chain) {
return chain.proceed(request.setAttribute(TENANT_ID_ATTRIBUTE_NAME, "tenantId"));
}
@Override
public int getOrder() {
return ServerFilterPhase.SECURITY.order();
}
}
And then in a controller:
@Get(produces = MediaType.APPLICATION_JSON)
public List<Item> list(@RequestAttribute(SecurityFilter.TENANT_ID_ATTRIBUTE_NAME) final String tenantId) {
return service.findAll(tenantId);
}