博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
week 6 CORS
阅读量:4589 次
发布时间:2019-06-09

本文共 4182 字,大约阅读时间需要 13 分钟。

1. CORS 简介

同源策略( same origin policy )是浏览器安全的基石。在同源策略的限制下,非同源的网站之间不能发送 ajax 请求的。

为了解决这个问题, w3c 提出了跨源资源共享,即 CORS()。

CORS 做到了两点:

  1. 不破坏即有规则
  2. 服务器实现了 CORS 接口,就可以跨源通信

基于这两点, CORS 将请求分为两类:简单请求和非简单请求。

1.1 简单请求

可以先看下 CORS 出现前的情况:跨源时能够通过 script 或者 image 标签触发 GET 请求或通过表单发送一条 POST 请求,但这两种请求 HTTP 头信息中都不能包含任何自定义字段。

简单请求对应该规则,因此对简单请求的定义为:

请求方法是 HEADGET 或 POST 且 HTTP 头信息不超过以下几个字段:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type(只限于 application/x-www-form-urlencodedmultipart/form-datatext/plain)。

比如有一个简单请求:

GET /test HTTP/1.1Accept: */*Accept-Encoding: gzip, deflate, sdch, brOrigin: http://www.examples.com Host: www.examples.com

对于这样的简单请求, CORS 的策略是请求时,在头信息中添加一个 Origin 字段,服务器收到请求后,根据该字段判断是否允许该请求。

  1. 如果允许,则在 HTTP 头信息中添加 Access-Control-Allow-Origin 字段,并返回正确的结果
  2. 如果不允许,则不在头信息中添加 Access-Control-Allow-Origin 字段。

浏览器先于用户得到返回结果,根据有无 Access-Control-Allow-Origin 字段来决定是否拦截该返回结果。

对于 CORS 出现前的一些服务, CORS 对他们的影响分两种情况:

  1. script 或者 image 触发的 GET 请求不包含 Origin 头,所以不受到 CORS 的限制,依旧可用。
  2. 如果是 ajax 请求, HTTP 头信息中会包含 Origin 字段,由于服务器没有做任何配置,所以返回结果不会包含 Access-Control-Allow-Origin,因此返回结果会被浏览器拦截,接口依旧不可以被 ajax 跨源访问。

可以看出, CORS 的出现,没有对”旧的“服务造成任何影响。

另外,除了提到的 Access-Control-Allow-Origin 还有几个字段用于描述 CORS 返回结果:

  1. Access-Control-Allow-Credentials: 可选,用户是否可以发送、处理 cookie 。
  2. Access-Control-Expose-Headers :可选,可以让用户拿到的字段。有几个字段无论设置与否都可以拿到的,包括: Cache-Control 、 Content-Language 、 Content-Type 、 Expires 、 Last-Modified 、 Pragma 。

1.2 非简单请求

除了简单请求之外的请求,就是非简单请求。

对于非简单请求的跨源请求,浏览器会在真实请求发出前,增加一次 OPTION 请求,称为预检请求( preflight request )。预检请求将真实请求的信息,包括请求方法、自定义头字段、源信息添加到 HTTP 头信息字段中,询问服务器是否允许这样的操作。

比如对于 DELETE 请求:

OPTIONS /test HTTP/1.1Origin: http://www.examples.comAccess-Control-Request-Method: DELETEAccess-Control-Request-Headers: X-Custom-Header Host: www.examples.com

与 CORS 相关的字段有:

  1. Access-Control-Request-Method: 真实请求使用的 HTTP 方法。
  2. Access-Control-Request-Headers: 真实请求中包含的自定义头字段。

服务器收到请求时,需要分别对 Origin 、 Access-Control-Request-Method 、 Access-Control-Request-Headers 进行验证,验证通过后,会在返回 Http 头信息中添加

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

他们的含义分别是:

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

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

服务端配置CORS

  1. 通过WebMvcConfigurerAdapter#addCorsMappings去配置

    public class WebConfig extends WebMvcConfigurerAdapter {     @Override     public void addCorsMappings(CorsRegistry registry) {         registry.addMapping("/**")                 .allowedHeaders("*")                 .allowedMethods("*")                 .allowedOrigins("*");     } }

     

  2. 通过自定义Filter

    @Bean public FilterRegistrationBean corsFilter() {     UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();     CorsConfiguration config = new CorsConfiguration();     config.addAllowedOrigin("*");     config.setAllowCredentials(true);     config.addAllowedHeader("*");     config.addAllowedMethod("*");     source.registerCorsConfiguration("/**", config);     FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));     bean.setOrder(0);     return bean; }

     

这两种方式实现的机制完全不一样,也就是产生作用的生命周期不一样。

  • 方式一,WebMvcConfigurerAdapter的配置最终将会转换为RequestMappingHandlerMapping,而这个Handler最终是被DispatcherServlet调用,也就是说,方式一的配置将会在Servlet中被调用。
  • 方式二,很容易理解,配置的Filter将会被springboot自动配置到Tomcat或其他web容器中。ServletContextInitializerBeans#addAdaptableBeans方法中,将自动查找spring容器中存在的Filter实现,并且根据@Order或Order来判断Filter的排序。

冲突

keycloak场景

前端已经通过javascript的接口,从keycloak验证并获得了token,keycloak作为单点登录系统,理论上是可以通过token登录并验证任何一个后端服务,但是,当按照文档上面的描述,正确配置springboot及security,后端依然无法通过token的验证。但当将前后端使用同一个IP和端口时,请求正常。

解决过程

  1. CORS同源配置。如上配置CORS,但请求依然。
  2. 打开浏览器debug,发现OPTIONS请求直接返回401,授权失败。此时如果先前已经了解CORS就不会产生疑问,CORS会将任何请求先切分为一个OPTIONS和一个原来的。
  3. 上一步表面OPTIONS请求被授权服务拦截,那么解决问题的方式就出来了。

解决方案

  • 方案一,配置Spring security策略,不拦截OPTIONS请求

    HttpSecurity#authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll()
  • 方案二,自定义CorsFilter,设置order为最高优先级或者其他,只需要优先级比Spring security的order高便好。

参考链接:

好的博文推荐:

转载于:https://www.cnblogs.com/EST-woah/p/10666560.html

你可能感兴趣的文章
图片加载机制比较
查看>>
Python scrapy爬取带验证码的列表数据
查看>>
MySQL数据库免安装版配置
查看>>
你必知必会的SQL面试题
查看>>
print输出带颜色
查看>>
GIT版本控制工具使用
查看>>
logback的使用和logback.xml详解
查看>>
做一个小总结吧,把别人的经验拿来总结一下
查看>>
CMake系列之一:概念
查看>>
html5 Canvas绘制时钟以及绘制运动的圆
查看>>
Unity3D热更新之LuaFramework篇[05]--Lua脚本调用c#以及如何在Lua中使用Dotween
查看>>
JavaScript空判断
查看>>
洛谷 P1439 【模板】最长公共子序列(DP,LIS?)
查看>>
python timeit
查看>>
Wireless Network 并查集
查看>>
51nod 1019 逆序数
查看>>
ubuntu 16 64位编译安装php
查看>>
架构之美01
查看>>
Web负载均衡
查看>>
SQL Server用表组织数据
查看>>