Cross-Origin跨域问题
为什么会跨域,要先了解浏览器的同源策略SOP(Same Orign Policy) https://segmentfault.com/a/1190000015597029
同源:
如果两个页面的协议,端口(如果有指定)和主机地址都相同,则两个页面具有相同的源。
协议/主机/端口
跨源网络访问
同源策略控制了不同源之间的交互,例如在使用XMLHttpRequest时会受到同源策略的约束。即同源策略限制了从一个源加载的文档或者脚本如何与另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
如果没有同源策略限制的接口请求则容易被CSRF攻击,下面是CSRF攻击的原理:
CORS
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。
- 所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。 对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。 - 实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
即CORS与普通请求代码一样。
CORS与JSONP相比
- JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
- 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
- JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。
CORS全称为Cross Origin Resource Sharing(跨域资源共享), 每一个页面需要返回一个名为Access-Control-Allow-Origin的http头来允许外域的站点访问,你可以仅仅暴露有限的资源和有限的外域站点访问。
我们可以理解为:如果一个请求需要允许跨域访问,则需要在http头中设置Access-Control-Allow-Origin来决定需要允许哪些站点来访问,如要允许www.baidu.com这个站点的请求跨域,则可以设置:
Access-Control-Allow-Origin:http://www.baidu.com
CROS跨域常用header
Access-Control-Allow-Origin: 允许哪些ip或域名可以跨域访问
Access-Control-Max-Age: 表示在多少秒之内不需要重复校验该请求的跨域访问权限
Access-Control-Allow-Methods: 表示允许跨域请求的HTTP方法,如:GET、POST、PUT、DELETE
Access-Control-Allow-Headers: 表示访问请求中允许携带哪些Header信息,如:Accept、Accept-Language、Content- Language、Content-Type
spring中解决跨域问题的方案:
注意:配置的允许跨域的域名、协议和端口后不要加 /
1、@CrossOrigin注解
此注解既可用于方法也可用于类
示例如下:
@CrossOrigin(origins = "http://www.zhihu.com") @RequestMapping(value = "/allProductions", method = RequestMethod.GET) public Result getAllOldProductions() { }
@CrossOrigin
注解既可注解在方法上,也可注解在类上。
2、XML全局配置
所有跨域请求都可以访问
<mvc:cors> <mvc:mapping path="/**" /> </mvc:cors>
更加细粒度的配置:
<mvc:cors> <mvc:mapping path="/api/**" allowed-origins="https://domain1.com, https://domain2.com" allowed-methods="GET, PUT" allowed-headers="header1, header2, header3" exposed-headers="header1, header2" allow-credentials="true" max-age="123" /> <mvc:mapping path="/resources/**" allowed-origins="https://domain1.com" /> </mvc:cors>
Springboot解决跨域问题配置
1、使用@CrossOrigin注解,同上
2、使用CorsFilter进行全局跨域配置
@Configuration public class GlobalCorsConfig { @Bean public CorsFilter corsFilter() { CorsConfiguration corsConfig = new CorsConfiguration(); // 开放哪些ip、端口、域名的访问权限,星号表示开放所有域 corsConfig.addAllowedOrigin("*"); // 允许发送cookie信息 corsConfig.setAllowCredentials(true); // 允许所有方法 corsConfig.addAllowedMethod("*"); // 允许get,post方法 // corsConfig.addAllowedMethod(HttpMethod.POST); // corsConfig.addAllowedMethod(HttpMethod.GET); // 允许HTTP请求头中携带哪些header信息 corsConfig.addAllowedHeader("*"); // 暴漏哪些头部信息(因为跨域访问默认不能获取全部头部信息) corsConfig.addExposedHeader("Content-Type"); // 添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfig); return new CorsFilter(source); } }
3、重写WebMvcConfigurer的addCorsMappings方法(全局跨域配置)
@Bean public WebMvcConfigurer crosConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") //对哪些映射路径应用跨域配置 .allowedOrigins("*") // 允许哪些域名访问 .allowCredentials(true) .allowedMethods("GET", "POST") .allowedHeaders("*") .exposedHeaders("Content-Type"); } }; }
或者:
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class GlobalCorsConfig implements WebMvcConfigurer{ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("HEAD", "GET", "POST", "PUT", "DELETE", "OPTIONS") .allowCredentials(true) .maxAge(3600) .allowedHeaders("*"); } }
4、过滤器实现
@Component public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse res = (HttpServletResponse) response; res.addHeader("Access-Control-Allow-Credentials", "true"); res.addHeader("Access-Control-Allow-Origin", "*"); res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); // res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN"); // CROS 复杂请求时会首先发送一个 OPTIONS 请求做嗅探,来测试服务器是否支持本次请求,请求成功后才会发送真实的请求;因此放行OPTIONS请求 if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) { response.getWriter().println("ok"); return; } chain.doFilter(request, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } }
END.