你能在 Spring 中完全禁用 CORS 支持吗?

Posted

技术标签:

【中文标题】你能在 Spring 中完全禁用 CORS 支持吗?【英文标题】:Can you completely disable CORS support in Spring? 【发布时间】:2017-11-25 15:26:51 【问题描述】:

如CORS preflight request fails due to a standard header 中所述,如果您向OPTIONS 端点发送请求并设置了OriginAccess-Control-Request-Method 标头,那么它们会被Spring 框架拦截,并且您的方法不会被执行。公认的解决方案是使用@CrossOrigin 注释来阻止Spring 返回403。但是,我正在使用 Swagger Codegen 生成我的 API 代码,所以我只想禁用它并手动实现我的 OPTIONS 响应。

那么你可以在 Spring 中禁用 CORS 拦截吗?

【问题讨论】:

【参考方案1】:

对于较新版本的 Spring Boot:

@Configuration
public class WebConfiguration implements WebMvcConfigurer 

    @Override
    public void addCorsMappings(CorsRegistry registry) 
        registry.addMapping("/**").allowedMethods("*");
    


Kotlin 方式

@Configuration
class WebConfiguration : WebMvcConfigurer 
    override fun addCorsMappings(registry: CorsRegistry) 
        registry.addMapping("/**").allowedMethods("*")
    

【讨论】:

【参考方案2】:

来自他们的documentation:

如果你使用的是 Spring Web MVC

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter 

    @Override
    public void addCorsMappings(CorsRegistry registry) 
        registry.addMapping("/**")
                .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
    

如果您使用的是 Spring Boot:

@Configuration
public class MyConfiguration 

    @Bean
    public WebMvcConfigurer corsConfigurer() 
        return new WebMvcConfigurerAdapter() 
            @Override
            public void addCorsMappings(CorsRegistry registry) 
                registry.addMapping("/**")
                        .allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
            
        ;
    

Yuriy Yunikov 的回答也是正确的。但我不喜欢“自定义”过滤器。

如果你有 Spring Web Security 给你带来麻烦。检查this SO 答案。

【讨论】:

此配置为所有来源和所有端点启用 CORS,发送“Access-Control-Allow-Origin: *”,这与禁用它相反。 从 Spring 5.0 开始,WebMvcConfigurerAdapter 已被弃用,而改用 WebMvcConfigurer。【参考方案3】:

尝试添加以下过滤器(您可以根据自己的需要和支持的方法自定义它):

@Component
public class CorsFilter extends OncePerRequestFilter 

    @Override
    protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response,
                                    final FilterChain filterChain) throws ServletException, IOException 
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, HEAD");
        response.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
        response.addHeader("Access-Control-Expose-Headers", "Access-Control-Allow-Origin, Access-Control-Allow-Credentials");
        response.addHeader("Access-Control-Allow-Credentials", "true");
        response.addIntHeader("Access-Control-Max-Age", 10);
        filterChain.doFilter(request, response);
    

【讨论】:

这篇文章被低估了!无论出于何种原因,我都无法让 CORS 在 spring-boot-starter-web 中工作......这篇文章解决了它! 这里也一样,花了几个小时解决了这个问题! 这里也一样,简洁明了。 同意。我正在使用所有 spring 文档,正是这一点使它对我有用。【参考方案4】:

我在我的 Spring Boot 应用程序中使用 Spring Security,并允许从特定域(或所有域)进行访问。

我的WebSecurityConfig

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 

    // ...

    @Override
    protected void configure(HttpSecurity http) throws Exception 

        // add http.cors()
        http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers("/get/**").permitAll()
                .antMatchers("/update/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
                .httpBasic(); // Authenticate users with HTTP basic authentication

        // REST is stateless
        http.sessionManagement()
               .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    

    // To enable CORS
    @Bean
    public CorsConfigurationSource corsConfigurationSource() 
        final CorsConfiguration configuration = new CorsConfiguration();

        configuration.setAllowedOrigins(ImmutableList.of("https://www.yourdomain.com")); // www - obligatory
//        configuration.setAllowedOrigins(ImmutableList.of("*"));  //set access from all domains
        configuration.setAllowedMethods(ImmutableList.of("GET", "POST", "PUT", "DELETE"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));

        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);

        return source;
    


有时需要在测试前清除浏览器历史记录。

详细信息可以在这里看到: http://appsdeveloperblog.com/crossorigin-restful-web-service/


仅适用于使用 Angular 的用户。从 Angular 我向后端运行请求:

export class HttpService 

  username = '..';
  password = '..';
  host = environment.api;
  uriUpdateTank = '/update/tank';

  headers: HttpHeaders = new HttpHeaders(
    'Content-Type': 'application/json',
    Authorization: 'Basic ' + btoa(this.username + ':' + this.password)
  );

  constructor(private http: HttpClient) 
  

  onInsertTank(tank: Tank) 
    return this.http.put(this.host + this.uriUpdateTank, tank, 
      headers: this.headers
    )
      .pipe(
        catchError(this.handleError)
      );
  
...


旧版本。 在我的 Spring Boot 应用程序中,没有其他方法可以工作:

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RequestFilter implements Filter 

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 

        HttpServletRequest request = (HttpServletRequest) req;
        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-Allow-Headers", "x-requested-with, x-auth-token");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        if (!(request.getMethod().equalsIgnoreCase("OPTIONS"))) 
            try 
                chain.doFilter(req, res);
             catch (Exception ex) 
                ex.printStackTrace();
            
         else 
            System.out.println("Pre-flight");
            response.setHeader("Access-Control-Allowed-Methods", "POST, GET, DELETE");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "authorization, content-type,x-auth-token, " +
                    "access-control-request-headers, access-control-request-method, accept, origin, authorization, x-requested-with");

            response.setStatus(HttpServletResponse.SC_OK);
        

    

    public void init(FilterConfig filterConfig) 
    

    public void destroy() 
    


【讨论】:

http.cors().and().csrf().disable() 这个工作就像魅力......干杯 所有其他“现代”方法都失败了,但这种“旧版本”方法成功了!非常感谢! @lukas84 为你高兴 :) @KirillCh 老是金子。这是唯一对我有用的方法。谢谢!【参考方案5】:

以前的答案几乎都是关于启用 CORS,这对我来说是禁用的。

@Configuration
public class MyConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.cors().and().csrf().disable();
    

    @Bean
    public WebMvcConfigurer corsConfigurer() 
        return new WebMvcConfigurer() 
            @Override
            public void addCorsMappings(CorsRegistry registry) 
                registry.addMapping("/**").allowedMethods("*");
            
        ;
    

【讨论】:

【参考方案6】:

如果你至少有 Java 8,试试这个:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues());
    

【讨论】:

【参考方案7】:

Spring MVC

https://docs.spring.io/spring-framework/docs/5.3.13/reference/html/web.html#mvc-cors-global-java
@Configuration(proxyBeanMethods = false)
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer 

    @Override
    public void addCorsMappings(CorsRegistry registry) 
        registry.addMapping("/**").allowedMethods("*").allowedHeaders("*");
    

春季启动

https://docs.spring.io/spring-boot/docs/2.5.7/reference/htmlsingle/#features.developing-web-applications.spring-mvc.cors
@Configuration(proxyBeanMethods = false)
public class MyConfiguration 

    @Bean
    public WebMvcConfigurer corsConfigurer() 
        return new WebMvcConfigurer() 
            @Override
            public void addCorsMappings(final CorsRegistry registry) 
                registry.addMapping("/**").allowedMethods("*").allowedHeaders("*");
            
        ;
    

Spring 安全性(使用 Spring MVC 或 Spring Boot)

https://docs.spring.io/spring-security/site/docs/5.5.3/reference/html5/#cors
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(final HttpSecurity http) throws Exception 
        // ...

        // see also: https://docs.spring.io/spring-security/site/docs/5.5.3/reference/html5/#csrf-when
        http.csrf().disabled();

        // if Spring MVC is on classpath and no CorsConfigurationSource is provided,
        // Spring Security will use CORS configuration provided to Spring MVC
        http.cors(Customizer.withDefaults());
    

【讨论】:

以上是关于你能在 Spring 中完全禁用 CORS 支持吗?的主要内容,如果未能解决你的问题,请参考以下文章

我应该在 Spring 后端禁用 CORS 吗?未经授权的请求被阻止

如何在 Spring Boot 安全性中禁用 CORS

如何在 Spring Boot 安全性中禁用 CORS

你能在每个块中捕获不止一种类型的异常吗? [复制]

Git:你能在master改变后更新分支吗?

AngularJS禁用CORS?