Javascript 如何在 Spring Boot + Spring Security 应用程序中配置 CORS?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36968963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to configure CORS in a Spring Boot + Spring Security application?
提问by Rudolf Schmidt
I use Spring Boot with Spring Security and Cors Support.
我使用带有 Spring Security 和 Cors 支持的 Spring Boot。
If I execute following code
如果我执行以下代码
url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
if xmlhttp.readyState is 4
console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:a'
do xmlhttp.send
I get as a result
结果我得到
200
If I test with wrong credentials like
如果我使用错误的凭据进行测试,例如
url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
if xmlhttp.readyState is 4
console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:aa'
do xmlhttp.send
instead of getting 401 (that is the standard code for wrong authentication in spring security) I get
我得到的不是 401(这是 Spring Security 中错误身份验证的标准代码)
0
with following browser notification:
带有以下浏览器通知:
GET http://localhost:5000/api/token
获取http://localhost:5000/api/token
XMLHttpRequest cannot load http://localhost:5000. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 401.
XMLHttpRequest 无法加载http://localhost:5000。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问Origin ' http://localhost:3000'。响应的 HTTP 状态代码为 401。
I'm developing front-end code that needs useful http status codes from server responses to handle the situation. I need something more useful than 0. Also the response body is empty. I dont know if my config is wrong, or it's a software bug and I also don't know where, if it's chromium (using arch linux) or spring security.
我正在开发前端代码,需要来自服务器响应的有用 http 状态代码来处理这种情况。我需要比 0 更有用的东西。而且响应体是空的。我不知道我的配置是错误的,还是软件错误,我也不知道在哪里,是铬(使用 arch linux)还是 spring 安全。
My Spring Config is:
我的弹簧配置是:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
@RequestMapping("api")
public class Controller {
@RequestMapping("token")
@CrossOrigin
Map<String, String> token(HttpSession session) {
return Collections.singletonMap("token", session.getId());
}
}
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("a").password("a").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().authenticated()
.and().httpBasic();
}
}
If I test with curl everything works perfect, I think because no CORS support needed, but I tried to simulate the CORS with OPTION requests and the result was also ok.
如果我使用 curl 测试一切正常,我认为是因为不需要 CORS 支持,但我尝试使用 OPTION 请求模拟 CORS,结果也不错。
$ curl -v localhost:5000/api/token -H "Authorization: Basic YTpha"
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTpha
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< 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
< Access-Control-Allow-Origin: http://localhost:3000
< Access-Control-Allow-Methods: POST,GET,OPTIONS,DELETE
< Access-Control-Max-Age: 3600
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Origin,Accept,X-Requested- With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization
< x-auth-token: 58e4cca9-7719-46c8-9180-2fc16aec8dff
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:15:44 GMT
<
* Connection #0 to host localhost left intact
{"token":"58e4cca9-7719-46c8-9180-2fc16aec8dff"}
and with wrong credentials:
并且凭据错误:
$ curl -v localhost:5000/api/token -H "Authorization: Basic YTp"
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTp
>
< HTTP/1.1 401 Unauthorized
< Server: Apache-Coyote/1.1
< 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
< WWW-Authenticate: Basic realm="Realm"
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:16:15 GMT
<
* Connection #0 to host localhost left intact
{"timestamp":1462119375041,"status":401,"error":"Unauthorized","message":"Failed to decode basic authentication token","path":"/api/token"}
Edit: To avoid misunderstandings. I use 1.3.3 Spring Boot. The Blog post writes:
编辑:为了避免误解。我使用 1.3.3 Spring Boot。博文写道:
CORS support will be available in the upcoming Spring Boot 1.3 release, and is already available in the 1.3.0.BUILD-SNAPSHOT builds.
Using controller method CORS configuration with @CrossOrigin annotations in your Spring Boot application does not require any specific configuration.
Global CORS configuration can be defined by registering a WebMvcConfigurer bean with a customized addCorsMappings(CorsRegistry) method:
CORS 支持将在即将发布的 Spring Boot 1.3 版本中提供,并且已经在 1.3.0.BUILD-SNAPSHOT 版本中提供。
在 Spring Boot 应用程序中使用带有 @CrossOrigin 注释的控制器方法 CORS 配置不需要任何特定配置。
可以通过使用自定义的 addCorsMappings(CorsRegistry) 方法注册 WebMvcConfigurer bean 来定义全局 CORS 配置:
I have added following code to enable global cors support. actually I have tried this before but it the result was the same. I tried it again recently and the result is the same.
我添加了以下代码以启用全局 cors 支持。实际上我以前试过这个,但结果是一样的。我最近又试了一次,结果是一样的。
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}
The idea, that the problem comes from a redirect between the authorization process is an interesting though. how can i change the redirect to any resources to avoid this conflict?
问题来自授权过程之间的重定向的想法很有趣。如何将重定向更改为任何资源以避免这种冲突?
EDIT:
编辑:
I guess I am closer to a solution. I have tested with my nodejs server that supports cors without problems by adding Access-Control-Allow-Origin: * to all requests.
我想我更接近解决方案。我已经使用我的 nodejs 服务器进行了测试,该服务器通过向所有请求添加 Access-Control-Allow-Origin: * 来毫无问题地支持 cors。
Like Stefan Isele has already mentioned it seems that spring security redirects or doesn't add the CORS header so that's why the request seems to be broken. So while spring security is checking the authentification it has to add the proper header.
就像 Stefan Isele 已经提到的那样,spring security 似乎重定向或不添加 CORS 标头,因此这就是请求似乎被破坏的原因。因此,当 Spring Security 正在检查身份验证时,它必须添加正确的标头。
Does anyone know how to do so?
有谁知道怎么做?
EDIT:
编辑:
I found a workaround, that seems to be ugly. I have started a github issue for spring boot where I describe the workaround: https://github.com/spring-projects/spring-boot/issues/5834
我找到了一个解决方法,这似乎很难看。我已经开始了 Spring Boot 的 github 问题,我描述了解决方法:https: //github.com/spring-projects/spring-boot/issues/5834
回答by Sébastien Deleuze
Spring Security can now leverage Spring MVC CORS support described in this blog postI wrote.
Spring Security 现在可以利用我写的这篇博文中描述的 Spring MVC CORS 支持。
To make it work, you need to explicitly enable CORS support at Spring Security level as following, otherwise CORS enabled requests may be blocked by Spring Security before reaching Spring MVC.
要使其工作,您需要在 Spring Security 级别显式启用 CORS 支持,如下所示,否则启用 CORS 的请求可能会在到达 Spring MVC 之前被 Spring Security 阻止。
If you are using controller level @CrossOrigin
annotations, you just have to enable Spring Security CORS support and it will leverage Spring MVC configuration:
如果您使用控制器级别的@CrossOrigin
注解,您只需要启用 Spring Security CORS 支持,它将利用 Spring MVC 配置:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
}
If you prefer using CORS global configuration, you can declare a CorsConfigurationSource
bean as following:
如果你更喜欢使用 CORS 全局配置,你可以声明一个CorsConfigurationSource
bean,如下所示:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()...
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
This approach supersedes the filter-based approachpreviously recommended.
这种方法取代了之前推荐的基于过滤器的方法。
You can find more details in the dedicated CORS sectionof Spring Security documentation.
您可以在Spring Security 文档的专用 CORS 部分中找到更多详细信息。
回答by zhouji
If you use JDK 8+, there is a one line lambda solution:
如果您使用 JDK 8+,则有一个单行 lambda 解决方案:
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
}
回答by Je Suis Alrick
If you are using Spring Security, you can do the following to ensure that CORS requests are handled first:
如果您使用的是Spring Security,您可以执行以下操作以确保首先处理 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;
}
}
See Spring 4.2.x CORSfor more information.
有关更多信息,请参阅Spring 4.2.x CORS。
WithoutSpring Security this will work:
如果没有Spring Security,这将起作用:
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "PUT", "POST", "PATCH", "DELETE", "OPTIONS");
}
};
}
回答by Stefan Isele - prefabware.com
Cross origin protection is a feature of the browser. Curl does not care for CORS, as you presumed. That explains why your curls are successful, while the browser requests are not.
跨源保护是浏览器的一项功能。正如您所推测的那样,Curl 不关心 CORS。这解释了为什么您的卷发成功,而浏览器请求却没有。
If you send the browser request with the wrong credentials, spring will try to forward the client to a login page. This response (off the login page) does not contain the header 'Access-Control-Allow-Origin' and the browser reacts as you describe.
如果您使用错误的凭据发送浏览器请求,spring 将尝试将客户端转发到登录页面。此响应(在登录页面之外)不包含标题“Access-Control-Allow-Origin”,浏览器会按照您的描述做出反应。
You must make spring to include the haeder for this login response, and may be for other response, like error pages etc.
您必须使 spring 包含此登录响应的 haeder,并且可能包含其他响应,例如错误页面等。
This can be done like this :
这可以这样做:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
}
This is copied from cors-support-in-spring-framework
这是从cors-support-in-spring-framework复制的
I would start by adding cors mapping for all resources with :
我将首先为所有资源添加 cors 映射:
registry.addMapping("/**")
and also allowing all methods headers.. Once it works you may start to reduce that again to the needed minimum.
并且还允许所有方法标头。一旦它起作用,您可以开始再次将其减少到所需的最小值。
Please note, that the CORS configuration changes with Release 4.2.
请注意,CORS 配置随 4.2 版而更改。
If this does not solve your issues, post the response you get from the failed ajax request.
如果这不能解决您的问题,请发布您从失败的 ajax 请求中获得的响应。
回答by ?zlem Gürses
I solved this problem by:
我通过以下方式解决了这个问题:
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CORSFilter extends CorsFilter {
public CORSFilter(CorsConfigurationSource source) {
super((CorsConfigurationSource) source);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Headers",
"Access-Control-Allow-Origin, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
if (response.getHeader("Access-Control-Allow-Origin") == null)
response.addHeader("Access-Control-Allow-Origin", "*");
filterChain.doFilter(request, response);
}
}
and:
和:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@Configuration
public class RestConfig {
@Bean
public CORSFilter corsFilter() {
CorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:4200");
config.addAllowedMethod(HttpMethod.DELETE);
config.addAllowedMethod(HttpMethod.GET);
config.addAllowedMethod(HttpMethod.OPTIONS);
config.addAllowedMethod(HttpMethod.PUT);
config.addAllowedMethod(HttpMethod.POST);
((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**", config);
return new CORSFilter(source);
}
}
回答by Hubert Grzeskowiak
Found an easy solution for Spring-Boot, Spring-Security and Java-based config:
为 Spring-Boot、Spring-Security 和基于 Java 的配置找到了一个简单的解决方案:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().configurationSource(new CorsConfigurationSource() {
@Override
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
return new CorsConfiguration().applyPermitDefaultValues();
}
});
}
}
回答by Radouane ROUFID
For properties configuration
对于属性配置
# ENDPOINTS CORS CONFIGURATION (EndpointCorsProperties)
endpoints.cors.allow-credentials= # Set whether credentials are supported. When not set, credentials are not supported.
endpoints.cors.allowed-headers= # Comma-separated list of headers to allow in a request. '*' allows all headers.
endpoints.cors.allowed-methods=GET # Comma-separated list of methods to allow. '*' allows all methods.
endpoints.cors.allowed-origins= # Comma-separated list of origins to allow. '*' allows all origins. When not set, CORS support is disabled.
endpoints.cors.exposed-headers= # Comma-separated list of headers to include in a response.
endpoints.cors.max-age=1800 # How long, in seconds, the response from a pre-flight request can be cached by clients.
回答by Toan Truong
I solved this problem by: `
我通过以下方式解决了这个问题:`
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Access-Control-Allow-Headers","Access-Control-Allow-Origin","Access-Control-Request-Method", "Access-Control-Request-Headers","Origin","Cache-Control", "Content-Type", "Authorization"));
configuration.setAllowedMethods(Arrays.asList("DELETE", "GET", "POST", "PATCH", "PUT"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
`
`
回答by Andres Navarro
Cors can be a pain in the ass, but with this simple code you are Cors ONLY!!!! to to specified method
Cors 可能很麻烦,但是使用这个简单的代码,您只是 Cors!!!!到指定的方法
@CrossOrigin(origins="*")// in this line add your url and thats is all for spring boot side
@GetMapping("/some")
public String index() {
return "pawned cors!!!!";
}
Like a charm in spring boot 2.0.2
就像 Spring Boot 2.0.2 中的魅力
回答by Sami Elhini
I was having major problems with Axios, Spring Boot and Spring Security with authentication.
我在使用 Axios、Spring Boot 和 Spring Security 进行身份验证时遇到了重大问题。
Please note the version of Spring Boot and the Spring Security you are using matters.
请注意您使用的 Spring Boot 版本和 Spring Security。
Spring Boot: 1.5.10 Spring: 4.3.14 Spring Security 4.2.4
春季启动:1.5.10 春季:4.3.14 春季安全 4.2.4
To resolve this issue using Annotation Based Java Configuration I created the following class:
为了使用基于注解的 Java 配置解决这个问题,我创建了以下类:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("youruser").password("yourpassword")
.authorities("ROLE_USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().
authorizeRequests()
.requestMatchers(CorsUtils:: isPreFlightRequest).permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.realmName("Biometrix");
http.csrf().disable();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Authorization"));
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
One of the major gotchas with Axios is that when your API requires authentication it sends an Authorization header with the OPTIONS request. If you do not include Authorization in the allowed headers configuration setting our OPTIONS request (aka PreFlight request) will fail and Axios will report an error.
Axios 的主要问题之一是,当您的 API 需要身份验证时,它会发送一个带有 OPTIONS 请求的 Authorization 标头。如果您在允许的标头配置设置中不包括 Authorization,我们的 OPTIONS 请求(又名 PreFlight 请求)将失败并且 Axios 将报告错误。
As you can see with a couple of simple and properly placed settings CORS configuration with SpringBoot is pretty easy.
正如您所看到的,使用 SpringBoot 进行几个简单且正确放置的设置 CORS 配置非常简单。