拦截器与过滤器的区别**
- 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规范中引入的接口,
具体了解可参考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());
}
}
}