spring boot过滤器FilterRegistrationBean

1,393 阅读1分钟

拦截器与过滤器的区别**

  • 1.拦截器是基于java反射机制的,而过滤器是基于函数回调的。
  • 2.过滤器基于servlet实现,过滤器的主要应用场景是对字符编码、跨域等问题进行过滤。 Servlet的工作原理是拦截配置好的客户端请求,然后对Request和Response进行处理。Filter过滤器随着web应用的启动而启动,只初始化一次。
  • 3.拦截器只对action起作用,而过滤器几乎可以对所有请求起作用。
  • 4.拦截器可以访问action上下文、值栈里的对象,而过滤器不能。
  • 5.在action的生命周期里,拦截器可以多起调用,而过滤器只能在容器初始化时调用一次。

拦截器的应用场景:权限控制,日志打印,参数校验

过滤器的应用场景:跨域问题解决,编码转换、token 校验

SpringBoot 提供的几种注册组件:

  • ServletRegistrationBean,
  • FilterRegistrationBean,
  • ServletListenerRegistrationBean,
  • DelegatingFilterProxyRegistrationBean

本篇来分析过滤器注册组件FilterRegistrationBean,

  • 1、FilterRegistrationBean加载机制
  • 2、自定义FilterChain

FilterRegistrationBean->

1、FilterRegistrationBean extends AbstractFilterRegistrationBean

2、DynamicRegistrationBean

3、RegistrationBean implements ServletContextInitializer, Ordered

ServletContextInitializer是 Servlet 容器初始化时所需的初始化接口,是servlet3.0规范中引入的接口,

image.png

具体了解可参考ServletContainerInitializer和ServletContext...的区别 - 知乎 (zhihu.com)

基于跨域代码应用

设置优先级

@ConditionalOnProperty(name = "demo.auth.enable", havingValue = "true")
@Configuration
public class DemoConfig {

@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
    CorsConfiguration corsConfiguration = new CorsConfiguration();
    corsConfiguration.setAllowCredentials(true);
    corsConfiguration.addAllowedOriginPattern("*");
    corsConfiguration.addAllowedHeader("*");
    corsConfiguration.addAllowedMethod("*");
    corsConfiguration.setMaxAge(3600L);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", corsConfiguration);
    FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>(new CorsFilter(source));
    registration.setOrder(INT_ONE);
    return registration;
}

@Bean
public CorsFilter corsFilter() {
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);
}

基于token代码应用


@ConditionalOnProperty(name = "app.demo.enable", havingValue = "true")
@Configuration
public class DemoFilterConfig {

    private static final String KEY_TOKEN_FILTER = "tokenFilter";
    private static final String URL_PATTERN_ALL = "/api/demo/*";
    @Bean
    public FilterRegistrationBean<TokenFilter> tokenFilterNewRegister(TokenFilter tokenFilter) {
        FilterRegistrationBean<TokenFilter> demo = new FilterRegistrationBean<>();
        frb.setFilter(tokenFilter); // 自定义过滤
        frb.addUrlPatterns(URL_PATTERN_ALL); //过滤路径
        frb.setName(KEY_TOKEN_FILTER); //过滤名称
        frb.setOrder(INT_TWO);//优先级
        return frb;
    }

    @Bean
    public TokenFilter tokenFilter() {
        return new TokenFilter();
    }

    @Slf4j
    public static class TokenFilter implements Filter {

      

        @Override
        public void doFilter(ServletRequest servletRequest
                , ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) servletRequest;
            HttpServletResponse resp = (HttpServletResponse) servletResponse;

            final String token = req.getHeader(AuthConstants.HTTP_USER_TOKEN);

            try {
                Objects.requireNonNull(token);
                //TODO  验证token的逻辑
                filterChain.doFilter(req, resp);
            } catch (Exception ex) {
                log.error(" tokenFiler validate token: [{}}]", token);
                this.writeFailureRestResponse(resp);
            }
        }

        private void writeFailureRestResponse(HttpServletResponse response) throws IOException {
            RestResponse<?> res = new RestResponse<>(0, "没有相应的权限");
            response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
            StreamUtils.copy(JSONObject.toJSONString(res, true), CharsetUtil.CHARSET_UTF_8, response.getOutputStream());
        }
    }
}