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
相关产品推荐
相关产品推荐

