CORS 是一个 W3C 标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了 AJAX 只能同源使用的限制(跨域资源共享 CORS 详解)。

解决 CORS 跨域方法大致有如下几类:

  • 使用 Nginx 代理配置转发请求。
  • 在 Zuul (配置允许敏感头信息等) 或  Spring Cloud Gateway 层配置跨域网关路由转发到资源端不涉及跨域。
  • Spring Boot 资源端配置以支持跨域(适用于无网关场景)。

Spring Boot 实现 CORS 跨域 (官方

  • 单个方法的跨域支持,可以使用 @CrossOrigin 的注解实现
  • 采用 JavaConfig 实现
  • 采用 Filter

但是如果项目中包含 Spring Security 就会有 401 的问题,Spring Security 本身是通过 Filter 实现的,如果没有对其单独做 CORS 的处理,在 Web Security 报错 401 的时候是不会返回相应的 CORS 的字段的。这会导致出现的 401 错误成为了一个无法进行跨域的错误,导致前端程序无法正常的处理 401 相应 。对于spring security oauth2 默认接口,例如 /oauth/token 跨域问题,可以通过全局 CORS Filter 解决。

@Configuration
public class GlobalCorsConfiguration { @Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
// corsConfiguration.addExposedHeader("head1");
//corsConfiguration.addExposedHeader("Location");
UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}

配置 CorsFilter 优先级与 Spring Security 不拦截 OPTIONS 请求

  • 配置 Spring Security 策略,不拦截 OPTIONS 请求
  • 自定义 CorsFilter,设置 order 优先级比 Spring Security 的 order 高。

配置服务器允许 /oauth/token的 OPTIONS 方法,因为 /oauth/token 接口是先发一个 OPTIONS 请求,然后再发送 POST请求,如果是 OPTIONS 接口不被允许,就会返回 401 错误。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(-1)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override
protected void configure(HttpSecurity http) throws Exception {
// http.requestMatchers().antMatchers(HttpMethod.OPTIONS, "/oauth/**","/login/**","/logout/**")
// .and()
// .authorizeRequests()
// .antMatchers().permitAll()
// .and()
// .formLogin().permitAll(); //新增login form 支持用户登录及授权 http.requestMatchers().antMatchers(HttpMethod.OPTIONS, "/oauth/**")
.and()
.cors()
.and()
.csrf().disable();
}
}

再次 Vue(vue-resource) 前端测试调用,问题解决。

this.$http.post('http://47.100.188.242:8888/oauth/token',
{'grant_type':'password','scope':'read','username':'test','password':'test'}
,{emulateJSON:true,headers:{Authorization: 'Basic Y2ssxpZW50Xzkd5c3VsuX3dlYjpzwZWNyZXRfOTlezdsW5fMTIzNDU2'}}).then(function(){ }, function(){ });

报文

OPTIONS http://localhost:8888/oauth/token HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: POST
Origin: http://localhost:5000
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36
Access-Control-Request-Headers: authorization
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9 HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://localhost:5000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: authorization
Access-Control-Allow-Credentials: true
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Thu, 27 Sep 2018 04:38:56 GMT -------------------------------------------------------------------
POST http://localhost:8888/oauth/token HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Content-Length: 60
Pragma: no-cache
Cache-Control: no-cache
Accept: */*
Origin: http://localhost:5000
Authorization: Basic Y2xpZW50Xzks5c3VuX3dlYjpzZWNyZXRfOsTlzdW5fMTIzNDUs2
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Referer: http://localhost:5000/test.html
Accept-Encoding: gzip, deflate, br grant_type=password&username=test&password=test&soap=api HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://localhost:5000
Access-Control-Allow-Credentials: true
Cache-Control: no-store
Pragma: no-cache
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
Content-Type: application/json;charset=UTF-8
Date: Thu, 27 Sep 2018 04:38:56 GMT
Content-Length: 1560 {"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJpcnZpbmciLCJzY29wZSI6WyJhbGwiLCJhcGkiLCJ1c2VyIiwicmVhZCIsIndyaXRlIl0sImV4dF9uYW1lIjoiaXJ2aW5nIiwiZXhwIjoxNTM4MDMwMjk4LCJjbGllbnRfbmFtZSI6ImlydmluZyIsImp0aSI6IjIwOTg1ZjJhLWNiMGUtNDRiZi1hZWIyLTYzMGQ5NWFhNDI3ZSIsImNsaWVudF9pZCI6ImNsaWVudF85OXN1bl93ZWIifQ.koBwYKeLGr0KgZkOAN9ENGtKtHyQnzBRR_b0N1Ck1g2hk5VOGKikBTcCf-HBycHDvFZzADyqzi1640JDWo7MwwZm72r4Ih_QN-A_CztAMLyxsMvotMx9Du4z8wOJ4qaOGEuFGj3HFdFaMG3ltaN1WnoxORolFLqd6O-Q21SUhXaOMldOUZ_AyQildNnJ3-EJSavVSEc78jnW0P5fEJtp7QpRTS6nyvwwQifD7uoshnPWWbAeX7rYfAhEie3m7csx6sB_7nnJavKyk_AUpddioOgvw8QDZSmIGPKDeLlFLNpq1NGssgCqECyxdwmWVCs3x7rr6CwRDFfva87moJQAIQ","token_type":"bearer","refresh_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJpcnZpbmciLCJzY29wZSI6WyJhbGwiLCJhcGkiLCJ1c2VyIiwicmVhZCIsIndyaXRlIl0sImF0aSI6IjIwOTg1ZjJhLWNiMGUtNDRiZi1hZWIyLTYzMGQ5NWFhNDI3ZSIsImV4dF9uYW1lIjoiaXJ2aW5nIiwiZXhwIjoxNTM4MDIzMjc1LCJjbGllbnRfbmFtZSI6ImlydmluZyIsImp0aSI6IjRiNTc1MTVlLWEwOTUtNGZiMS05MGQ3LTE0MjQyOTcyMWI1YyIsImNsaWVudF9pZCI6ImNsaWVudF85OXN1bl93ZWIifQ.E8gviZsAb8ci_PMAzj4Oj7bqopr8xNwG3LAwa-pi987yVhg7CTlDhD0QOZLqHVPViwMY7dql-j2ccefwpZsfeaL4i1x5xouANoJ-zRJi7aruxJ_3guy2Ln0fReEYnOnkzKRGjWkdeCbxmrFgg0TkDASB_vTsegsbjqpVfCRg7LAvIcZwQCj1uiSqV8jaHbadvZpA1yZXt7lOMILHwtKkcEOkM7xDUbCHrG1J6qNjRNRbZhI34xXzP0EdXq8_FBA-ykpI1NWTt8jqYtQJfjyZCb9StcQmTqIq234d1ES6uiyZz-pqaiAo7qiVbrK85uOPmuCzuYtZcbWs8neiDeL8_g","expires_in":7161,"scope":"all api user read write","client_name":"irving","ext_name":"irving","jti":"20985f2a-cb0e-44bf-aeb2-630d95aa427e"}

备注:

Spring Security 文档中 (https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors)定义的方式。

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override
protected void configure(HttpSecurity http) throws Exception {
http
// by default uses a Bean by the name of corsConfigurationSource
.cors().and()
...
} @Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}

Spring Cloud Gateway (http://cloud.spring.io/spring-cloud-gateway/single/spring-cloud-gateway.html#_cors_configuration)

spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "docs.spring.io"
allowedMethods:
- GET

ZUUL

https://cloud.spring.io/spring-cloud-static/spring-cloud-netflix/2.1.0.M3/single/spring-cloud-netflix.html#_enabling_cross_origin_requests

@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/path-1/**")
.allowedOrigins("http://allowed-origin.com")
.allowedMethods("GET", "POST");
}
};
}

REFER:
https://aisensiy.github.io/2017/11/08/spring-cors-and-security/
http://www.spring4all.com/article/177
https://blog.csdn.net/GeorgeShaw1/article/details/75089734
https://stackoverflow.com/questions/37516755/spring-boot-rest-service-options-401-on-oauth-token
https://github.com/pagekit/vue-resource
http://cloud.spring.io/spring-cloud-gateway/single/spring-cloud-gateway.html#_cors_configuration

关于 Spring Security OAuth2 中 CORS 跨域问题的更多相关文章

  1. 关于 Spring Security OAuth2 中 Feign 调用 Token 问题

    微服务体系中,避免不了服务之间链式调用,一般使用 Feign ,由于使用 Spring Security OAuth2 全局做了安全认证,简单的一种实现方式就是在服务提供方获得 Token 再次通过 ...

  2. Spring MVC 4.2 CORS 跨域访问

    跨站 HTTP 请求(Cross-site HTTP request)是指发起请求的资源所在域不同于该请求所指向资源所在的域的 HTTP 请求.比如说,域名A(http://domaina.examp ...

  3. Spring Boot+AngularJS中因为跨域导致Session丢失

    http://blog.csdn.net/dalangzhonghangxing/article/details/52446821 如果还在为跨域问题烦恼,请查看博主的 解决angular+sprin ...

  4. .NET中CORS跨域访问WebApi

    我这里只写基本用法以作记录,具体为什么看下面的文章: http://www.cnblogs.com/landeanfen/p/5177176.html http://www.cnblogs.com/m ...

  5. 禁止chrome中CORS跨域资源共享错误

    在开发中,可以通过命令行命令chrome --allow-file-access-from-files来 禁止CORS错误. 只在紧急情况下使用这个方法,比如你的老板正站在你身后, 并且所有事情都无法 ...

  6. 使用Spring MVC测试Spring Security Oauth2 API

    不是因为看到希望了才去坚持,而坚持了才知道没有希望. 前言 在Spring Security源码分析十一:Spring Security OAuth2整合JWT和Spring Boot 2.0 整合 ...

  7. Spring Boot 中使用 Spring Security, OAuth2 跨域问题 (自己挖的坑)

    使用 Spring Boot 开发 API 使用 Spring Security + OAuth2 + JWT 鉴权,已经在 Controller 配置允许跨域: @RestController @C ...

  8. Spring Boot 2中对于CORS跨域访问的快速支持

    原文:https://www.jianshu.com/p/840b4f83c3b5 目前的程序开发,大部分都采用前后台分离.这样一来,就都会碰到跨域资源共享CORS的问题.Spring Boot 2 ...

  9. CORS跨域请求规则以及在Spring中的实现

    CORS: 通常情况下浏览器禁止AJAX从外部获取资源,因此就衍生了CORS这一标准体系,来实现跨域请求. CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origi ...

随机推荐

  1. 对Java单例设计模式中懒汉式类定义的讨论

    全世界人民都知道单例设计模式中类的定义分为懒汉式和饿汉式两种,然而今天并不是要把它们做横向比较.实际上,不论饿汉式类的代码看起来有多么美轮美奂,在实际开发中它的效率总是不如懒汉式的.然而在笔试和面试中 ...

  2. No rule to make target '/usr/lib/x86_64-linux-gnu/libproj.so ,needed by '../bin/generate_pointcloud解决方法

    这是/usr/lib/x86_64-linux-gnu/文件夹内没有这个libproj.so 库,先在该文件夹内搜索是否有同名不同版本的库,如果有 ,可以使用ln -s在该文件夹内部对存在的库链接到一 ...

  3. 使用kbmmw 的REST 服务实现上传大文件

    我们在使用kbmmw的REST 服务时,经常会下载和上传大文件.例如100M以上的.kbmmw的rest服务中 提供标准的文件下载,上传功能,基本上就是打开文件,发送,接收,没有做特殊处理.这些对于文 ...

  4. docker部署pinpoint

    pinpoint-collector部署 Dockerfile FROM tomcat8:jdk8 MAINTAINER limugen<limugen@uce.cn> ENV APP_H ...

  5. gulp使用详解

    前面整理了 gulp使用入门,本节介绍相关的压缩 1.压缩js文件 步骤同基础步骤,相关可以看入门篇 npm install gulp-uglify --save-dev 引入js压缩库 gulpfi ...

  6. DOTween的基本用法

    首先声明一点,不要简单的认为 DOTween 只能用在 Transform 组件上完成一些简单的动画,或者是完成一些 UI 动画,DOTween 的用途是很广的,unity中有很多组件都可以使用 DO ...

  7. ExtJS中获取选中行的数据

    listeners: { select:function(rowModel,record){ var data = rowModel.getLastSelected(); console.log(&q ...

  8. 2019年华南理工校赛(春季赛)--L--剪刀石头布(签到)

    #include <iostream> using namespace std; int main(){ string a,b,c,d; a="Scissors"; b ...

  9. 海龟绘图turtle库之二级基础编程题

    一.画一个太极图 import turtle as t t.pensize(2)#设置笔画宽度 t.circle(100)#以100为半径的圆 t.circle(50, 180) t.circle(- ...

  10. ArcSDE

    ArcSDE,即数据通路,是ArcGIS的空间数据引擎,它是在关系数据库管理系统(RDBMS)中存储和管理多用户空间数据库的通路.从空间数据管理的角度看,ArcSDE是一个连续的空间数据模型,借助这一 ...