如何使AuthFilter仅在标注@FilterThisRequest的方法前执行?
嘿,这个场景我之前处理过好几次,给你几个可行的方案,还有更优的替代思路:
方案一:改造现有的AuthFilter实现注解匹配
因为你用的是继承GenericFilterBean的Servlet过滤器,它是在Spring MVC处理请求之前执行的,默认拿不到控制器方法上的注解信息。所以需要先通过请求路径找到对应的处理器方法,再判断是否存在目标注解。
具体步骤:
让过滤器能获取Spring容器的Bean
给你的AuthFilter加上@Component,同时通过SpringBeanAutowiringSupport实现自动注入Spring的RequestMappingHandlerMapping(它能根据请求找到对应的控制器方法):@Component public class AuthFilter extends GenericFilterBean { @Autowired private RequestMappingHandlerMapping requestMappingHandlerMapping; @Override protected void initFilterBean() throws ServletException { // 确保Spring自动注入生效 SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HandlerMethod handlerMethod = getTargetHandlerMethod(request); // 判断方法或类上是否有@FilterThisRequest注解 boolean needFilter = false; if (handlerMethod != null) { needFilter = handlerMethod.hasMethodAnnotation(FilterThisRequest.class) || handlerMethod.getBeanType().isAnnotationPresent(FilterThisRequest.class); } if (!needFilter) { // 没有注解,直接放行 chain.doFilter(req, res); return; } // 有注解,执行你的认证业务逻辑 // ... 这里放原来AuthFilter里的校验代码 chain.doFilter(req, res); } private HandlerMethod getTargetHandlerMethod(HttpServletRequest request) { try { // 通过RequestMappingHandlerMapping获取当前请求对应的处理器 Object handler = requestMappingHandlerMapping.getHandler(request).getHandler(); if (handler instanceof HandlerMethod) { return (HandlerMethod) handler; } } catch (Exception e) { // 非控制器请求(比如静态资源)直接返回null return null; } return null; } }注册过滤器
在Spring Boot中可以用FilterRegistrationBean注册,让它拦截所有请求,内部通过注解判断是否执行逻辑:@Configuration public class FilterConfig { @Bean public FilterRegistrationBean<AuthFilter> authFilterRegistration(AuthFilter authFilter) { FilterRegistrationBean<AuthFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(authFilter); registration.addUrlPatterns("/*"); registration.setOrder(Ordered.HIGHEST_PRECEDENCE); return registration; } }
方案二:更优替代——使用Spring MVC的HandlerInterceptor
Servlet过滤器是Servlet容器层面的组件,而HandlerInterceptor是Spring MVC原生的拦截器,天生就能拿到控制器方法的信息,代码会简洁很多,更贴合Spring生态:
实现拦截器
@Component public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; // 检查方法或类上的注解 boolean needAuth = handlerMethod.hasMethodAnnotation(FilterThisRequest.class) || handlerMethod.getBeanType().isAnnotationPresent(FilterThisRequest.class); if (needAuth) { // 执行你的认证逻辑 // ... 比如校验token、权限 // 如果认证失败,可以直接返回错误:response.sendError(HttpServletResponse.SC_UNAUTHORIZED); // 然后返回false阻止请求继续执行 } } return true; // 放行请求 } }注册拦截器
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private AuthInterceptor authInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authInterceptor) .addPathPatterns("/**"); // 拦截所有请求,内部通过注解判断是否执行逻辑 } }
方案三:通用方法拦截——使用AOP切面
如果你的认证逻辑不仅要作用于控制器方法,还需要拦截服务层、DAO层等其他方法,AOP切面会是更灵活的选择:
@Aspect @Component public class AuthAspect { // 匹配带有@FilterThisRequest注解的方法,或者所在类带有该注解的方法 @Before("@annotation(com.yourpackage.FilterThisRequest) || @within(com.yourpackage.FilterThisRequest)") public void beforeMethod(JoinPoint joinPoint) { // 执行认证逻辑 // 可以通过joinPoint获取方法名、参数、目标对象等信息 // 如果认证失败,直接抛出自定义异常即可:throw new UnauthorizedException("认证失败"); } }
方案选择建议
- 若仅针对控制器请求做拦截,优先选
HandlerInterceptor,代码更简洁,无需处理Servlet层面的细节。 - 若必须用Servlet过滤器(比如需要在Spring MVC处理前修改请求参数、处理非Spring MVC请求),则用方案一的改造方式。
- 若需要跨多层的方法拦截(比如服务层、工具类方法),选AOP切面更合适。
内容的提问来源于stack exchange,提问作者JVic
相关产品推荐
相关产品推荐

