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. 【机器学习】异常检测算法(I)

    在给定的数据集,我们假设数据是正常的 ,现在需要知道新给的数据Xtest中不属于该组数据的几率p(X). 异常检测主要用来识别欺骗,例如通过之前的数据来识别新一次的数据是否存在异常,比如根据一个用户以 ...

  2. Python基础------列表,元组的调用方法

    Python基础------列表,元组的调用方法@@@ 一. 列表 Python中的列表和歌曲列表类似,也是由一系列的按特定顺序排列的元素组成的,在内容上,可以将整数,实数,字符串,列表,元组等任何类 ...

  3. python3+ selenium3开发环境搭建

    环境搭建 基于python3和selenium3做自动化测试,俗话说:工欲善其事必先利其器:没有金刚钻就不揽那瓷器活,磨刀不误砍柴工,因此你必须会搭建基本的开发环境,掌握python基本的语法和一个I ...

  4. 工作我们是专业的之css规范

    我一直认为专业是一种态度.不同于业余,专业代表无论技术高低都会遵守一定的规范,专业代表对某一领域不断的精益求精.专业就是比业余逼格高. 习惯书写规范 css 属性声明的顺序:Positioning(定 ...

  5. 前台js接收后台的json数据

    后台返回的json数据,如php的: return json_encode($data); 在前台 js接收如下: function json2object(str){ var jsstr = str ...

  6. Unity3D编辑器扩展(二)——定义自己的窗口

    上一篇我们讲了如何定义菜单按钮 https://www.cnblogs.com/xiaoyulong/p/10115053.html 这一篇我们讲如何定义自己的窗口. 定义窗口我们需要继承 Edito ...

  7. retrofit+rxjava封装

    public class RetrofitHelper { private static OkHttpClient okHttpClient; private static ServiceAPI se ...

  8. matplotlib&numpy画图

    import numpy as np import matplotlib.pyplot as plt x=np.linspace(0,6,100) y=np.cos(2*np.pi*x)*np.exp ...

  9. Maven3-依赖

    依赖配置 我们先来看一份简单的依赖声明: <project> ... <dependencies> <dependency> <groupId>...& ...

  10. win7安装Oracle 11g 详细教程

    一.下载 可以去Oracle官网下载:http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.htm ...