CORSFilter过滤器作用于自定义过滤器之后造成的跨域问题(SpringBean IOC执行优先级)

CORSFilter过滤器作用于自定义过滤器之后造成的跨域问题

介绍

项目中使用了自定义的Filter,然后加了用于解决前端跨域问题的CORSFilter配置,之前可能不存在跨域验证Token的问题,这次突然前端访问全部报了Token验证失败问题,“没有携带令牌”,因为跨域而造成的Token拿不到,但是已经配置了CORSFilter允许Cookie跨域等,进而开始排查之路。

背景

  1. 前端访问后端接口,报未携带令牌(Token);
  2. 登录后仍无效,登录逻辑无问题;
  3. 本地调试接口无问题。

问题分析

  1. 前端请求是否携带Token验证参数;
  2. 后端是否收到请求,收到请求之后参数验证报错出处;
  3. 是否跨域问题,跨域配置是否生效。

排查确认

  1. 前端请求查看,浏览器f12,请求参数正常;在这里插入图片描述在这里插入图片描述

  2. 后端输出日志查看,是没有找到Token,但是此处是自定义Filter的逻辑,说明后端收到了请求,在自定义Filter处理,并结束此次调用;

  3. 在自定义Filter的doFilter方法处打断电debugger,走进方法,Jwt验证Token时,相关验证参数为null,说明并没有接收到Token验证的参数,可能是跨域问题了;在这里插入图片描述

  4. 找到配置的CORSFilter,进入CORSFilter,在doFilterInternal()处打断点,发现并没有走进来,是没有生效吗?还是因为自定义的Filter已经结束了访问,CORSFilter还没执行?

  5. 从本地访问登录接口,成功;然后发现了问题,请求先经过自定义Filter处理完,再把请求过滤到了CORSFilter,这时候进入到了之前打的断点doFilterInternal()开始处理,最后返回。在这里插入图片描述

  6. 问题发现,自定义的Filter和启用的CORSFilter在加载到IOC后的执行的顺序是:自定义FIlter →CORSFilter,所以会造成跨域请求时,还未经过CORSFilter处理就先过滤到自定义Filter中,跨域的Cookie相关参数无法拿到。

问题解决

思路:保证优先进入CorsFilter控制逻辑,保证跨域请求参数到达。
**注意:**自定义Filter不仅注册了Component,也加了@Order注解,将优先级设置到最低,确仍然执行在CORSFilter之前(自定义的Filter,内含Token验证逻辑)。
解决方式:配置CORSFilter时,设置执行优先级高于自定义过滤器的优先级。
下面是修改之前和之后的代码:

  1. 自定义过滤器未修改
// 自定义接口访问验证,内含Token验证逻辑
@Order(Ordered.LOWEST_PRECEDENCE)
@Component
public class GatewayFilter implements Filter {
    
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    
    
        ....
    }
}
  1. 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);
    }
}
  1. 修改实现方式并增加优先级控制
// 修改后的
@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;
    }
}

总结

  1. 遇到类似问题要根据经验和现场情况把握造成事故发生的大致原因;
  2. 根据事故场景及还原确定具体翻车主责方,前端还是后端;
  3. 根据监控确定确定事故影响主要原因,Token无法得到,跨域拦截;
  4. 排查出现这种情况的形式和原理,再以此解决问题。
    注意:@Order、Ordered不影响类的加载顺序而是影响Bean加载到IOC容器之后执行的顺序(优先级);

相关知识

参考: 浅谈Spring @Order注解的使用.
参考: Spring Security拦截器引起Java CORS跨域失败的问题.
参考: springboot 配置过滤器Filter及控制多个Filter的执行顺序.

Guess you like

Origin blog.csdn.net/huofuman960209/article/details/114735155