You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Micronaut客户端请求添加自定义Token头及过滤器执行顺序异常问题咨询

解决Micronaut中ClientCredentialsHttpClientFilter与自定义过滤器的执行顺序问题

我之前也碰到过类似的坑,尤其是用native镜像构建后过滤器顺序乱掉的情况。核心问题在于Micronaut默认的过滤器排序逻辑(通常按类名字母序)在native环境下会因为GraalVM的元数据优化、类加载顺序变化失效,导致你的自定义过滤器抢在官方的ClientCredentialsHttpClientFilter前面执行,自然读不到令牌值。

下面是两种可靠的解决方案,能确保官方过滤器优先执行:

1. 使用@Order注解指定优先级

Micronaut的@Order注解可以明确控制过滤器的执行顺序——数值越小,优先级越高。官方的ClientCredentialsHttpClientFilter默认用的优先级是SecurityFilterOrder.DEFAULT_CLIENT_CREDENTIALS_FILTER(常量值为-100),我们只需要给自定义过滤器设置一个比这个值大的数值,就能保证它在官方过滤器之后执行。

示例代码:

import io.micronaut.core.order.Order;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MutableHttpRequest;
import io.micronaut.http.filter.HttpClientFilter;
import io.micronaut.http.filter.ClientFilterChain;
import io.micronaut.security.filter.SecurityFilterOrder;
import org.reactivestreams.Publisher;

@Order(SecurityFilterOrder.DEFAULT_CLIENT_CREDENTIALS_FILTER + 1)
public class CustomTokenHeaderFilter implements HttpClientFilter {

    @Override
    public Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> request, ClientFilterChain chain) {
        String authHeader = request.getHeaders().get("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            request.header("X-Custom-Token", token); // 替换成你的自定义头名称
        }
        return chain.proceed(request);
    }
}

2. 实现Ordered接口

如果你更喜欢代码层面的配置,也可以让自定义过滤器实现Ordered接口,重写getOrder()方法返回同样的优先级数值:

import io.micronaut.core.order.Ordered;
import io.micronaut.http.HttpResponse;
import io.micronaut.http.MutableHttpRequest;
import io.micronaut.http.filter.HttpClientFilter;
import io.micronaut.http.filter.ClientFilterChain;
import io.micronaut.security.filter.SecurityFilterOrder;
import org.reactivestreams.Publisher;

public class CustomTokenHeaderFilter implements HttpClientFilter, Ordered {

    @Override
    public int getOrder() {
        return SecurityFilterOrder.DEFAULT_CLIENT_CREDENTIALS_FILTER + 1;
    }

    @Override
    public Publisher<? extends HttpResponse<?>> doFilter(MutableHttpRequest<?> request, ClientFilterChain chain) {
        // 同上面的逻辑
        String authHeader = request.getHeaders().get("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            request.header("X-Custom-Token", token);
        }
        return chain.proceed(request);
    }
}

为什么这能解决native镜像的问题?

在IDE运行时,Micronaut的类加载和元数据是完整的,默认排序可能刚好符合预期,但native镜像构建时,GraalVM会进行类名混淆、元数据裁剪等大量优化,这会破坏默认的排序逻辑。显式指定@Order或实现Ordered接口后,Micronaut会在native镜像构建时保留这些优先级元数据,确保过滤器按预期顺序执行。

你可以在两个过滤器中加日志输出验证顺序,比如分别打印ClientCredentialsHttpClientFilter 正在执行和CustomTokenHeaderFilter 正在执行,确认官方过滤器先跑。

内容的提问来源于stack exchange,提问作者Swapnil Dhimmar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 07:24:04