SpringSecurity-15-解决跨域访问
什么是跨域
举例说明跨域,当一个请求url的协议、域名、端口三个之中任意一个和当前页面的url不同就是跨域
当前url | 被请求url | 是否跨域 | 理由 |
---|---|---|---|
http://mp.weixin.qq.com | http://mp.weixin.qq.com/index.html | 否 | |
协议、域名、端口相同 | |||
http://mp.weixin.qq.com | https://mp.weixin.qq.com/index.html | 跨域 | 协议不同(http/https) |
http://mp.weixin.qq.com | http://www.baidu.com | 跨域 | 域名不同 |
http://mp.weixin.qq.com | http://www.weixin.qq.com | 跨域 | 子域名不同 |
http://mp.weixin.qq.com:8888 | http://mp.weixin.qq.com:9999 | 跨域 | 端口不同 |
跨域的限制
如果请求url和当前页面非同源,会对以下三种行为做出限制:
-
Cookie、LocalStorage和IndexDB无法读取
-
DOM无法获取
-
AJAX请求不能发送
解决跨域方式
JSONP解决跨域
JSONP是解决服务器和客户端跨域相互访问的常用方法。特点是简单实用,老式浏览器全部支持,服务器改造小。
基本思路是在网页端添加一个<script>
原有,向服务器请求JSON数据,这种做法没有同源政策的限制,服务器收到请求后,将数据放在指定的回调函数中传到前端页面。具体步骤:
- 在网页端插入
<script>
元素
<script>
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) {
console.log('Your public IP address is: ' + data.ip);
};
</script>
- 服务器收到请求后,将数据放在回调函数返回到页面
foo({
"ip": "8.8.8.8"
});
注:JSONP只支持GET请求跨域,局限比较大。
CORS
CORS(Cross-Origin Resource Sharing)的规范中有一组新增的HTTP首部字段,允许服务器声明其 提供的资源允许哪些站点跨域使用。是解决AJAX跨域请求的根本解决方法。浏览器发出CORS请求的时候需要在信息头中添加Origin
字段。浏览器请求中的CORS字段有以下:
request部分:
//下面两个只有预检请求会带
-
Access-Control-Request-Method : //告诉服务器我要用什么方法,服务器会根据配置做下筛选 再返回一个Access-Control-Allow-Methods告诉浏览器哪些可以用
-
Access-Control-Request-Headers: //告诉服务器我要带哪些header,服务器会根据配置做下筛选 再返回一个Access-Control-Allow-Headers告诉浏览器哪些可以
response部分:
-
Access-Control-Allow-Origin:他的值可以是请求时
Origin
字段的值,也可以是*
,表示接受任意域名的请求 -
Access-Control-Allow-Credentials:是一个boolean值,表示十分允许发送Cookie,默认情况CORS中不包括Cookie,如果设置为
true
,表示服务器允许Cookie包含在请求中。 -
Access-Control-Expose-Headers:
XMLHttpRequest
对象的getResponseHeader()
方法只能拿到6个基本字段:Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
。如果想拿到其他字段,就必须在Access-Control-Expose-Headers
里面指定。上面的例子指定,getResponseHeader('TestBar')
可以返回TestBar
字段的值 -
Access-Control-Allow-Methods:它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法,如POST GET.
-
Access-Control-Allow-Headers:如果浏览器请求包括
Access-Control-Request-Headers
字段,则Access-Control-Allow-Headers
字段是必需的。 -
Access-Control-Max-Age:告诉浏览器多久不需要再发出预检请求
Spring Security 中的配置CORS
- 添加GlobalCorsConfig配置文件来允许跨域访问,覆盖默认的CorsFilter来解决该问题
/**
* 允许跨域调用的过滤器
*/
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
//允许所有域名进行跨域调用
config.addAllowedOrigin("*");
//允许跨域发送cookie
config.setAllowCredentials(true);
//放行全部原始头信息
config.addAllowedHeader("*");
//允许所有请求方法跨域调用
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
- Spring Security为我们提供了一种新的CORS规则的配置方法:CorsConfigurationSource 。使用这种方法实现的注入一个CorsFilter过滤器。
@Bean
public CorsConfigurationSource corsConfigurationSource(){
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://www.baidu.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**",configuration);
return source;
}
注:这两种方法选择一种就可以。