javamicronautmicronaut-rest

Adding headers to incoming request in Micronaut filters


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?


Solution

  • 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);
    }