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

如何使AuthFilter仅在标注@FilterThisRequest的方法前执行?

嘿,这个场景我之前处理过好几次,给你几个可行的方案,还有更优的替代思路:

方案一:改造现有的AuthFilter实现注解匹配

因为你用的是继承GenericFilterBean的Servlet过滤器,它是在Spring MVC处理请求之前执行的,默认拿不到控制器方法上的注解信息。所以需要先通过请求路径找到对应的处理器方法,再判断是否存在目标注解。

具体步骤:

  1. 让过滤器能获取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;
        }
    }
    
  2. 注册过滤器
    在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生态:

  1. 实现拦截器

    @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; // 放行请求
        }
    }
    
  2. 注册拦截器

    @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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:14:22