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

10 篇文章 0 订阅
1 篇文章 0 订阅

项目场景:

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)
	                    }
                    })

在这里插入图片描述


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring BootShiro 中,可以通过自定义过滤器来解决跨域问题。具体步骤如下: 1. 创建自定义跨域过滤器 创建一个类,继承 org.apache.shiro.web.filter.authc.FormAuthenticationFilter,实现 doFilterInternal 方法。代码如下: ```java public class CorsAuthenticationFilter extends FormAuthenticationFilter { @Override protected void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { HttpServletResponse httpServletResponse = (HttpServletResponse) response; HttpServletRequest httpServletRequest = (HttpServletRequest) request; // 允许跨域访问的域名 String[] allowedOrigins = {"http://localhost:8080"}; // 允许的请求类型 String allowedMethods = "GET,POST,PUT,DELETE,OPTIONS"; // 允许的头信息 String allowedHeaders = "Content-Type, Authorization"; httpServletResponse.setHeader("Access-Control-Allow-Origin", String.join(",", allowedOrigins)); httpServletResponse.setHeader("Access-Control-Allow-Methods", allowedMethods); httpServletResponse.setHeader("Access-Control-Allow-Headers", allowedHeaders); // 如果是预检请求,直接返回成功 if (httpServletRequest.getMethod().equalsIgnoreCase("OPTIONS")) { httpServletResponse.setStatus(HttpServletResponse.SC_OK); return; } super.doFilterInternal(request, response, chain); } } ``` 这里的 allowedOrigins 配置是允许的跨域地址,allowedMethods 配置是允许的 HTTP 方法,allowedHeaders 配置是允许的 HTTP 头信息。如果收到的请求是预检请求,直接返回成功即可。 2. 在 Shiro 配置中添加自定义过滤器Shiro 的配置文件中添加自定义过滤器。例如: ```java @Bean public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean(); // ... Map<String, Filter> filters = new LinkedHashMap<>(); filters.put("corsAuthenticationFilter", new CorsAuthenticationFilter()); filterFactoryBean.setFilters(filters); // ... return filterFactoryBean; } ``` 这里将自定义过滤器 CorsAuthenticationFilter 添加到了 Shiro过滤器链中。 3. 配置 Spring Boot跨域设置 在 Spring Boot 的配置文件中添加 CORS 的配置,跟上面的一样。 这样配置完后,就可以跨域访问 Shiro 中的接口了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值