springboot前后端分离跨域的坑,跨域cookie的引用,跨域过滤器与其他过滤器的冲突(集成shiro的跨域问题)

本文探讨了Spring Boot中的跨域问题及解决方案,包括不同跨域配置方式的对比与实践,特别是跨域过滤器的优先级调整,以及如何正确设置跨域cookie。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目场景:

springboot+shiro+redis+jwt前后端分离,整合思路正在逐步完善,本篇只讨论整合过程中的前后端分离跨域的一些问题和坑


问题描述:

  1. springboot中几种跨域方式的区别,以及个人认为最正常的处理
  2. 坑我一晚上的问题:过滤器之间的优先级,尤其对于跨域过滤器尤为重要
  3. 前后端分离后,跨域cookie传送的解决办法

问题分析:

1. springboot的几种跨域方式:
  • 实现WebMvcConfigurer或子类的addCorsMappings方式
    可以理解为类似于拦截器,但又不是拦截器,因为他与拦截器同时存在时,跨域会冲突甚至失效
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").
                allowedOriginPatterns("*"). //允许跨域的域名,可以用*表示允许任何域名使用
//                allowedOrigins("*").    //在Springboot2.4对应Spring5.3后在设置allowCredentials(true)的基础上不能直接使用通配符设置allowedOrigins,而是需要指定特定的URL。如果需要设置通配符,需要通过allowedOriginPatterns指定
                allowedMethods("GET", "POST", "DELETE", "PUT") . //允许任何方法(post、get等)
                allowedHeaders("*"). //允许任何请求头
                allowCredentials(true). //带上cookie信息
                exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L); //maxAge(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果
    }
}
  • 使用spring内置的CorsFilter,凡是过滤器都会有坑,下面解答
    spring为我们提供了他内置的corsFilter,我们只需要填入相应参数即可使用,他的本质是Filter过滤器,不是拦截器,属于servlet范畴。
	/**
     * 配置跨域过滤器
     */
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("http://localhost:9999");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(corsConfigurationSource);
    }
  • 使用传统自定义Filter,同样过滤器都有坑
    这个就不用细说了,跨域处理的开山鼻祖,谁都知道,记得实现Filter接口,在此只贴出部分代码
 	@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, HEAD");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With");
        filterChain.doFilter(servletRequest, servletResponse);
    }
2.过滤器优先级之间的关系:

       简单来说,就是如果你定义了其他过滤器去进行请求拦截的逻辑,同时也定义了跨域过滤器,如果跨域优先级不够,那么,请求就不会进入跨域过滤器,虽然被拦截,但它不会报错,而去显示跨域错误。这么说有点笼统,我用自己的实例来说明。
       本项目使用了shiro+jwt,自然而然会去重写shiro的Filter去拦截没有登录和授权的用户,同时我这里还需要跨域。那么,仔细想想,过滤器也有顺序链。如果一个请求被shiro的过滤器拦截,他没有进入到跨域过滤器中就已经被拦截,那么此时,无论你返回什么,前端都只会显示跨域失败的错误。也就是这样在这里插入图片描述
       你甚至可以显而易见的看到,我返回的状态码为200,200代表请求成功。我的本意是如果没有登录则返回未登录的json信息·······
       原因就是,这个请求没有进入跨域过滤器中。

       解决方案:

       大家都知道,filter有一个order属性,他是设置优先级的,order值越小优先级越高。说到这儿大家应该已经明白,让跨域过滤器优先级最高就好,这里我就不说传统方法了,大家举一反三

	/**
     * 配置跨域过滤器,跨域过滤器一定要限制性
     */
    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.addAllowedOrigin("http://localhost:9999");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        FilterRegistrationBean<CorsFilter> corsFilterFilterRegistrationBean = new FilterRegistrationBean<>(new CorsFilter(corsConfigurationSource));
        //重点在此
        corsFilterFilterRegistrationBean.setOrder(0);
        return corsFilterFilterRegistrationBean;
    }
3.跨域cookie的携带:

       由于最近的项目都是前后端分离。jwt或token的存储已经试过localStorage、sessionStorage、Cookie。也查阅了许多资料,也看了大多网站的处理办法。基于三者的安全考虑的话(三者安全大家自行查阅,百度一抓一把),cookie是相对最安全的。但是跨域cookie的处理初学者包括我也很头痛。具体原理不知道,我现在只知道怎么做。
       首先后端跨域处理是必须的,同时,跨域时必须让一个属性打开,也就是,对应上面的跨域处理的第二种方法

corsConfiguration.setAllowCredentials(true);

       至于对应的请求头,大家自行百度。
       前端处理也很好说,建议封装ajax等等,这样比较方便,这里只贴出jquery的处理。重点:不仅请求的接口需要带上,获取cookie的接口也必须写上,否则,浏览器会忽略。其他ajax方式,类似,基本上都是这个属性

				$.ajax({
	                    url: "http://localhost/test",
                        xhrFields: {
                            withCredentials: true 	
                        },
                        crossDomain: true,
	                    success: function (data) {
                            console.log(data)
	                    }
                    })

在这里插入图片描述


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值