CORSFilter过滤器作用于自定义过滤器之后造成的跨域问题(SpringBean IOC执行优先级)
CORSFilter过滤器作用于自定义过滤器之后造成的跨域问题介绍背景问题分析排查确认问题解决总结相关知识介绍项目中使用了自定义的Filter,然后加了用于解决前端跨域问题的CORSFilter配置,之前可能不存在跨域验证Token的问题,这次突然前端访问全部报了Token验证失败问题,“没有携带令牌”,因为跨域而造成的Token拿不到,但是已经配置了CORSFilter允许Cookie跨域等,进
介绍
项目中使用了自定义的Filter,然后加了用于解决前端跨域问题的CORSFilter配置,之前可能不存在跨域验证Token的问题,这次突然前端访问全部报了Token验证失败问题,“没有携带令牌”,因为跨域而造成的Token拿不到,但是已经配置了CORSFilter允许Cookie跨域等,进而开始排查之路。
背景
- 前端访问后端接口,报未携带令牌(Token);
- 登录后仍无效,登录逻辑无问题;
- 本地调试接口无问题。
问题分析
- 前端请求是否携带Token验证参数;
- 后端是否收到请求,收到请求之后参数验证报错出处;
- 是否跨域问题,跨域配置是否生效。
排查确认
-
前端请求查看,浏览器f12,请求参数正常;
-
后端输出日志查看,是没有找到Token,但是此处是自定义Filter的逻辑,说明后端收到了请求,在自定义Filter处理,并结束此次调用;
-
在自定义Filter的doFilter方法处打断电debugger,走进方法,Jwt验证Token时,相关验证参数为null,说明并没有接收到Token验证的参数,可能是跨域问题了;
-
找到配置的CORSFilter,进入CORSFilter,在doFilterInternal()处打断点,发现并没有走进来,是没有生效吗?还是因为自定义的Filter已经结束了访问,CORSFilter还没执行?
-
从本地访问登录接口,成功;然后发现了问题,请求先经过自定义Filter处理完,再把请求过滤到了CORSFilter,这时候进入到了之前打的断点doFilterInternal()开始处理,最后返回。
-
问题发现,自定义的Filter和启用的CORSFilter在加载到IOC后的执行的顺序是:自定义FIlter →CORSFilter,所以会造成跨域请求时,还未经过CORSFilter处理就先过滤到自定义Filter中,跨域的Cookie相关参数无法拿到。
问题解决
思路:保证优先进入CorsFilter控制逻辑,保证跨域请求参数到达。
**注意:**自定义Filter不仅注册了Component,也加了@Order注解,将优先级设置到最低,确仍然执行在CORSFilter之前(自定义的Filter,内含Token验证逻辑)。
解决方式:配置CORSFilter时,设置执行优先级高于自定义过滤器的优先级。
下面是修改之前和之后的代码:
- 自定义过滤器未修改
// 自定义接口访问验证,内含Token验证逻辑
@Order(Ordered.LOWEST_PRECEDENCE)
@Component
public class GatewayFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
....
}
}
- CORSFilter原配置(未设置优先级方式)
// 原CORSFilter
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 允许cookies跨域
config.setAllowCredentials(true);
// #允许向该服务器提交请求的URI,*表示全部允许,自定义可以添加多个,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedOrigin("*");
// #允许访问的头信息,*表示全部,可以添加多个
config.addAllowedHeader("*");
// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.setMaxAge(1800L);
// 允许提交请求的方法,*表示全部允许,一般OPTIONS,GET,POST三个够了
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//对所有接口都有效
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
- 修改实现方式并增加优先级控制
// 修改后的
@Configuration
public class CorsConfig {
@Bean
public FilterRegistrationBean corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // 允许cookies跨域
config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,自定义可以添加多个,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedHeader("*");// #允许访问的头信息,*表示全部,可以添加多个
config.setMaxAge(1800L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.addAllowedMethod("*");// 允许提交请求的方法,*表示全部允许,一般OPTIONS,GET,POST三个够了
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);//对所有接口都有效
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(Ordered.LOWEST_PRECEDENCE); // 优先级最高
return bean;
}
}
总结
- 遇到类似问题要根据经验和现场情况把握造成事故发生的大致原因;
- 根据事故场景及还原确定具体翻车主责方,前端还是后端;
- 根据监控确定确定事故影响主要原因,Token无法得到,跨域拦截;
- 排查出现这种情况的形式和原理,再以此解决问题。
注意:@Order、Ordered不影响类的加载顺序而是影响Bean加载到IOC容器之后执行的顺序(优先级);
相关知识
参考: 浅谈Spring @Order注解的使用.
参考: Spring Security拦截器引起Java CORS跨域失败的问题.
参考: springboot 配置过滤器Filter及控制多个Filter的执行顺序.
更多推荐
所有评论(0)