Spring Boot 安全 CORS
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40286549/
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
Spring Boot Security CORS
提问by user1935987
I have a problem with CORS filter on spring security URL's.
It doesn't set Access-Control-Allow-Origin
and other exposed header on URL's belonging to spring sec (login/logout) or filtered by Spring Security.
我在 spring 安全 URL 上的 CORS 过滤器有问题。它不会Access-Control-Allow-Origin
在属于 spring sec(登录/注销)或由 Spring Security 过滤的 URL 上设置和其他公开的标头。
Here are the configurations.
这是配置。
CORS:
CORS:
@Configuration
@EnableWebMvc
public class MyWebMvcConfig extends WebMvcConfigurerAdapter {
********some irrelevant configs************
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/*").allowedOrigins("*").allowedMethods("GET", "POST", "OPTIONS", "PUT")
.allowedHeaders("Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method",
"Access-Control-Request-Headers")
.exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials")
.allowCredentials(true).maxAge(3600);
}
}
Security:
安全:
@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
.formLogin()
.successHandler(ajaxSuccessHandler)
.failureHandler(ajaxFailureHandler)
.loginProcessingUrl("/authentication")
.passwordParameter("password")
.usernameParameter("username")
.and()
.logout()
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/authentication").permitAll()
.antMatchers("/oauth/token").permitAll()
.antMatchers("/admin/*").access("hasRole('ROLE_ADMIN')")
.antMatchers("/user/*").access("hasRole('ROLE_USER')");
}
}
So, if I make a request to the url's which are not listened by security - CORS headers are set. Spring security URL's - not set.
因此,如果我向安全性未侦听的 url 发出请求,则会设置 CORS 标头。Spring 安全 URL - 未设置。
Spring boot 1.4.1
弹簧靴 1.4.1
回答by mika
Instead of using the CorsRegistry you can write your own CorsFilter and add it to your security configuration.
您可以编写自己的 CorsFilter 并将其添加到您的安全配置中,而不是使用 CorsRegistry。
Custom CorsFilter class:
自定义 CorsFilter 类:
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request= (HttpServletRequest) servletRequest;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Allow-Credentials", true);
response.setHeader("Access-Control-Max-Age", 180);
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
Security config class:
安全配置类:
@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
CorsFilter corsFilter() {
CorsFilter filter = new CorsFilter();
return filter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(corsFilter(), SessionManagementFilter.class) //adds your custom CorsFilter
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
.formLogin()
.successHandler(ajaxSuccessHandler)
.failureHandler(ajaxFailureHandler)
.loginProcessingUrl("/authentication")
.passwordParameter("password")
.usernameParameter("username")
.and()
.logout()
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/authentication").permitAll()
.antMatchers("/oauth/token").permitAll()
.antMatchers("/admin/*").access("hasRole('ROLE_ADMIN')")
.antMatchers("/user/*").access("hasRole('ROLE_USER')");
}
}
回答by The Gilbert Arenas Dagger
Option 1 (Use WebMvcConfigurer bean):
选项 1(使用 WebMvcConfigurer bean):
The CORS configuration that you started with is not the proper way to do it with Spring Boot. You need to register a WebMvcConfigurer
bean. Reference here.
您开始使用的 CORS 配置不是使用 Spring Boot 进行配置的正确方法。你需要注册一个WebMvcConfigurer
bean。参考这里。
Example Spring Boot CORS configuration:
Spring Boot CORS 配置示例:
@Configuration
@Profile("dev")
public class DevConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:4200");
}
};
}
}
This will provide the CORS configuration for a basic (no security starter) Spring Boot application. Note that CORS support exists independent of Spring Security.
这将为基本(无安全启动器)Spring Boot 应用程序提供 CORS 配置。请注意,CORS 支持独立于 Spring Security 存在。
Once you introduce Spring Security, you need to register CORS with your security configuration. Spring Security is smart enough to pick up your existing CORS configuration.
引入 Spring Security 后,您需要使用安全配置注册 CORS。Spring Security 足够聪明,可以选择您现有的 CORS 配置。
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
....
Option 2 (Use CorsConfigurationSource bean):
选项 2(使用 CorsConfigurationSource bean):
The first option I described is really from the perspective of adding Spring Security to an existing application. If you are adding Spring Security from the get-go, the way that is outlined in the Spring Security Docsinvolves adding a CorsConfigurationSource bean.
我描述的第一个选项实际上是从将 Spring Security 添加到现有应用程序的角度来看的。如果您从一开始就添加 Spring Security,则Spring Security Docs 中概述的方法涉及添加 CorsConfigurationSource bean。
@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;
}
}
回答by sisanared
I have a React
based web client, and my backend REST API is running Spring Boot
Ver 1.5.2
我有一个React
基于 Web 的客户端,我的后端 REST API 运行的是Spring Boot
1.5.2 版
I wanted to quickly enable CORS
on all controller route requests from my client running on localhost:8080
. Inside my security configuration, I simply added a @Bean
of type FilterRegistrationBean
and got it working easily.
我想快速启用CORS
来自我的客户端运行的所有控制器路由请求localhost:8080
。在我的安全配置中,我简单地添加了一个@Bean
类型FilterRegistrationBean
并让它轻松工作。
Here is the code:
这是代码:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AuthConfiguration extends WebSecurityConfigurerAdapter {
....
....
@Bean
public FilterRegistrationBean corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin(corsAllowedOrigin); // @Value: http://localhost:8080
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // **permit OPTIONS call to all**
....
}
....
....
}
You can refer Spring Boot docs here
回答by Dennis Kieselhorst
Currently the OPTIONS requests are blocked by default if security is enabled.
当前,如果启用了安全性,则默认情况下会阻止 OPTIONS 请求。
Just add an additional bean and preflight requests will be handled correctly:
只需添加一个额外的 bean,预检请求就会得到正确处理:
@Bean
public IgnoredRequestCustomizer optionsIgnoredRequestsCustomizer() {
return configurer -> {
List<RequestMatcher> matchers = new ArrayList<>();
matchers.add(new AntPathRequestMatcher("/**", "OPTIONS"));
configurer.requestMatchers(new OrRequestMatcher(matchers));
};
}
Please note that depending on your application this may open it for potential exploits.
请注意,根据您的应用程序,这可能会打开它以进行潜在的攻击。
Opened issue for a better solution: https://github.com/spring-projects/spring-security/issues/4448
打开问题以获得更好的解决方案:https: //github.com/spring-projects/spring-security/issues/4448
回答by Neeraj
If you need it for quick local development just add this annotation on your controller. (offcourse change origins as required)
如果您需要它进行快速本地开发,只需在您的控制器上添加此注释。(根据需要更改原点)
@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
回答by Jhoan Manuel Mu?oz Serrano
I just had a similar issue, I was trying to execute a request from my frontend in React executing on http://localhost:3000, to my backend in SpringBoot executing at http://localhost:8080. I had two errors:
我刚刚遇到了一个类似的问题,我试图从我在http://localhost:3000上执行的 React 前端执行一个请求,到我在http://localhost:8080 上执行的 SpringBoot 后端。我有两个错误:
Access Control Allow Origin
访问控制允许来源
I solved this very easily by adding this to my RestController:
我通过将它添加到我的 RestController 很容易地解决了这个问题:
@CrossOrigin(origins = ["http://localhost:3000"])
After fixing this, I started getting this error: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true'
修复此问题后,我开始收到此错误: 响应中“Access-Control-Allow-Credentials”标头的值为“”,必须为“true”
Access-Control-Allow-Credentials
访问控制允许凭据
This one can be worked around in two ways:
可以通过两种方式解决此问题:
Adding
allowCredentials = "true"
to the CrossOrigin configuration:@CrossOrigin(origins = ["http://localhost:3000"], allowCredentials = "true")
Changing the credential options of the fetch in the frontend request. Basically, you'll need to perform the fetch call like this:
fetch('http://localhost:8080/your/api', { credentials: 'same-origin' })
添加
allowCredentials = "true"
到 CrossOrigin 配置:@CrossOrigin(origins = ["http://localhost:3000"], allowCredentials = "true")
更改前端请求中提取的凭据选项。基本上,您需要像这样执行 fetch 调用:
fetch('http://localhost:8080/your/api', { credentials: 'same-origin' })
Hope this helps =)
希望这会有所帮助 =)
回答by Jason Fitzpatrick
You could also achieve this with an interceptor.
您也可以使用拦截器来实现这一点。
Use the exception to ensure you are ending the lifecycle of the request:
使用异常来确保您正在结束请求的生命周期:
@ResponseStatus (
value = HttpStatus.NO_CONTENT
)
public class CorsException extends RuntimeException
{
}
Then, in your interceptor, set headers for all OPTIONS requests and throw the exception:
然后,在拦截器中,为所有 OPTIONS 请求设置标头并抛出异常:
public class CorsMiddleware extends HandlerInterceptorAdapter
{
@Override
public boolean preHandle (
HttpServletRequest request,
HttpServletResponse response,
Object handler
) throws Exception
{
if (request.getMethod().equals("OPTIONS")) {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Methods","GET, POST, PUT, OPTIONS, DELETE");
response.addHeader("Access-Control-Allow-Headers", "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,Authorization,If-Modified-Since,Cache-Control,Content-Type");
response.addHeader("Access-Control-Max-Age", "3600");
response.addHeader("charset", "utf-8");
throw new CorsException();
}
return super.preHandle(request, response, handler);
}
}
Lastly, apply the interceptor to all routes:
最后,将拦截器应用于所有路由:
@Configuration
public class MiddlewareConfig extends WebMvcConfigurerAdapter
{
@Override
public void addInterceptors (InterceptorRegistry registry)
{
registry.addInterceptor(new CorsMiddleware())
.addPathPatterns("/**");
}
}
回答by Dach0
If anyone struggles with the same problem in 2020. here's what did the work for me. This app is for learning purposes so I have enabled everything
如果有人在 2020 年遇到同样的问题。这对我有用。这个应用程序是为了学习目的,所以我启用了一切
CorsFilter class:
CorsFilter 类:
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Content-Length, X-Requested-With");
chain.doFilter(req, res);
}
@Override
public void destroy() {
}
}
and then again setup of headers in class extending WebSecurityConfigurerAdapter:
然后在扩展 WebSecurityConfigurerAdapter 的类中再次设置标头:
@Configuration
@EnableWebSecurity
public class SpringSecurityConfigurationBasicAuth extends WebSecurityConfigurerAdapter {
@Bean
CorsFilter corsFilter() {
CorsFilter filter = new CorsFilter();
return filter;
}
protected void configure(HttpSecurity http) throws Exception {
System.out.println("Im configuring it");
(
(HttpSecurity)
(
(HttpSecurity)
(
(ExpressionUrlAuthorizationConfigurer.AuthorizedUrl)
http
.headers().addHeaderWriter(
new StaticHeadersWriter("Access-Control-Allow-Origin", "*")).and()
.addFilterBefore(corsFilter(), SessionManagementFilter.class)
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
.anyRequest()
).authenticated().and()
).formLogin().and()
).httpBasic();
}
}
回答by Ikechukwu Eze
This is quite clean and doesn't require any extra configurations. Pass asterisks where you want all option to be valid (like I did in setAllowedHeaders).
这很干净,不需要任何额外的配置。在您希望所有选项都有效的地方传递星号(就像我在 setAllowedHeaders 中所做的那样)。
@EnableWebSecurity
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().configurationSource(request -> {
var cors = new CorsConfiguration();
cors.setAllowedOrigins(List.of("http://localhost:4200", "http://127.0.0.1:80", "http://example.com"));
cors.setAllowedMethods(List.of("GET","POST", "PUT", "DELETE", "OPTIONS"));
cors.setAllowedHeaders(List.of("*"));
return cors;
}).and()...
}
}