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

SpringBoot集成Micrometer:为Meter添加认证用户标签失败问题

解决Micrometer MeterFilter中获取Authentication为null的问题

问题根源

MeterFilter的map方法执行时机晚于请求的FilterChain生命周期:当请求处理完成后,Spring Security会调用SecurityContextHolder.clearContext()清空安全上下文,而Micrometer的指标加工(包括MeterFilter的处理)通常在这之后触发,此时SecurityContext已经被清理,自然无法获取到Authentication对象。

解决方案

方案一:通过拦截器提前保存用户信息到请求属性

在请求处理过程中(SecurityContext未被清空时),将用户信息存入请求属性,后续MeterFilter读取该属性添加标签:

// 自定义拦截器,在请求处理后保存用户信息
@Component
public class UserMetricTagInterceptor implements HandlerInterceptor {
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && request.getRequestURI().contains("/api")) {
            request.setAttribute("metric_user", auth.getName());
        }
    }
}

// 注册拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private UserMetricTagInterceptor userMetricTagInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(userMetricTagInterceptor)
                .addPathPatterns("/api/**");
    }
}

// 修改MeterFilter读取请求属性
@Bean
public MeterFilter meterFilter() {
    return (id) -> {
        String uri = id.getTag("uri");
        if (uri != null && uri.contains("/api")) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                String userName = (String) attributes.getRequest().getAttribute("metric_user");
                if (userName != null) {
                    return id.withTags(Tags.of("user", userName));
                }
            }
        }
        return id;
    };
}

方案二:自定义WebMvcTagsContributor(推荐)

利用Micrometer针对WebMvc的扩展机制,在请求处理过程中直接添加用户标签,此时SecurityContext仍有效:

@Component
public class UserWebMvcTagsContributor implements WebMvcTagsContributor {
    @Override
    public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable exception) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null && request.getRequestURI().contains("/api")) {
            return Tags.of("user", auth.getName());
        }
        return Tags.empty();
    }

    @Override
    public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler) {
        return getTags(request, response, handler, null);
    }
}

Spring Boot的WebMvcMetricsAutoConfiguration会自动识别并应用这个自定义TagsContributor,无需额外配置即可将用户标签添加到所有WebMvc相关指标中。

注意事项

  • 若涉及异步请求处理,需确保RequestContextHolder的属性能传递到异步线程中,可通过设置RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true)实现属性继承。
  • 对于非WebMvc类型的自定义指标(如手动创建的Timer),需在创建指标时(SecurityContext存在的时机)手动添加用户标签。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 09:05:28