Micronaut客户端请求添加自定义Token头及过滤器执行顺序异常问题咨询
我之前也碰到过类似的坑,尤其是用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

