【has been blocked by CORS policy】 解决后端使用spring boot + spring security 框架时的跨域问题

CORS 简介

在解决问题之前先了解一下什么是CORS, CORS即为了解决浏览器同源问题,W3C 提出的跨源资源共享,即 CORS(Cross-Origin Resource Sharing)。也就是在前后端分离的情况下,后端服务允许前端服务访问自己的资源。
CORS 做到了如下两点:
不破坏即有规则
服务器实现了 CORS 接口,就可以跨源通信

Access-Control-Allow-Origin: http://www.examples.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000

所以解决跨域问题的基本思路就是在请求头中加入以上内容:
每个header 的值可以根据自己的需求指定,也可以使用 “*” 代替,表示全部通过
他们的含义分别是:

  1. Access-Control-Allow-Methods: 真实请求允许的方法
  2. Access-Control-Allow-Headers: 服务器允许使用的字段
  3. Access-Control-Allow-Credentials: 是否允许用户发送、处理 cookie
  4. Access-Control-Max-Age: 预检请求的有效期,单位为秒。有效期内,不会重复发送预检请求

当预检请求通过后,浏览器会发送真实请求到服务器。这就实现了跨源请求。

Spring boot + Spring security 跨域问题

有些时候我们可能遇到本来在spring boot 应用中通过CorsFilter 或者拦截器 配置了跨域,用的好好地,但是加入spring security 后跨域失效了的情况。

对于简单请求:
浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
下面是一个例子,浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个Origin字段

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0…

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

对于非简单请求:
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

在实际应用中,由于前后端分离并且使用了security ,前端发送的请求头中需要添加 authorization 或者 token 的字段,因此会触发浏览器在发送请求之前会发送一个 OPTION 方法的预检请求。

则原先spring boot中的跨域配置就可能失效了,无法给预检请求返回 http OK。所以汇报跨域错误。

正确配置方式

方式1:

在SecurityConfig中配置开启CORS, 亲测有效

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 允许跨域访问
        http.cors();
    }

默认会找name为corsConfigurationSource的bean

@Bean
pubilc CorsConfigurationSource CorsConfigurationSource() {
    CorsConfigurationSource source =   new UrlBasedCorsConfigurationSource();
    CorsConfiguration corsConfiguration = new CorsConfiguration();
    corsConfiguration.addAllowedOrigin("*");	//同源配置,*表示任何请求都视为同源,若需指定ip和端口可以改为如“localhost:8080”,多个以“,”分隔;
    corsConfiguration.addAllowedHeader("*");//header,允许哪些header,本案中使用的是token,此处可将*替换为token;
    corsConfiguration.addAllowedMethod("*");	//允许的请求方法,PSOT、GET等
    ((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**",corsConfiguration); //配置允许跨域访问的url
    return source;
}
方式2

通过过滤器全局配置跨域
但是需要确保CORSFilter 的位置要在 spring security 验证用户密码的Filter 之前,这样才能在请求投中添加到跨域相关的字段,是预检请求通过,然后发送正式请求。

http.addFilterBefore(customCorsFilter, UsernamePasswordAuthenticationFilter.class);

customCorsFilter为过滤器,具体实现方式如下:

@Configuration
public class GlobalCorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        //1.添加CORS配置信息
        CorsConfiguration config =new CorsConfiguration();
          //放行哪些原始域
          config.addAllowedOrigin("*");
          //是否发送Cookie信息
          config.setAllowCredentials(true);
          //放行哪些原始域(请求方式)
          config.addAllowedMethod("*");
          //放行哪些原始域(头部信息
          config.addAllowedHeader("*");
          //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
          config.addExposedHeader("*");
 
        //2.添加映射路径
        UrlBasedCorsConfigurationSource configSource =new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);
 
        //3.返回新的CorsFilter.
        return new CorsFilter(configSource);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值