Spring Boot:CORS问题

13

我正在使用Spring Boot 2.0.2 Release版本。以下是我的安全配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        prePostEnabled = true,
        securedEnabled = true,
        jsr250Enabled = true)
@ComponentScan("com.mk")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AuthenticationProvider myAuthenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.cors().configurationSource(corsConfigurationSource())
                .and()
                .csrf().disable()
                .anonymous().and()
                .authorizeRequests()
                .antMatchers(HttpMethod.GET,"/index.html").permitAll()
                .antMatchers(HttpMethod.POST,"/login").permitAll()
                .antMatchers(HttpMethod.GET,"*").authenticated()
                .and().httpBasic();
    }
    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

由于CORS问题,我无法调用任何API(包括允许所有操作的登录API)。

在浏览器中,我会收到以下错误信息(使用Postman可以正常工作,因为它不进行CORS检查):

无法加载http://localhost:8080/myurl: 预检请求未通过访问控制检查:所请求的资源缺少'Access-Control-Allow-Origin'头信息。 因此,源'http://localhost:4200'被禁止访问。 响应的HTTP状态码为403。

4个回答

13
尽管Spring Security提供了在http配置器中配置CORS的方法,但是添加CORS过滤器到应用程序会更加简洁 -

虽然Spring Security提供了一种在http配置器中配置CORS的方式,但将CORS过滤器添加到应用程序中会更加简洁 -

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


@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
    response.setHeader("Access-Control-Allow-Credentials", "true");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");

    chain.doFilter(req, res);
}

@Override
public void init(FilterConfig filterConfig) {
}

@Override
public void destroy() {
}

}

将优先级最高的过滤器排序,确保javax.servlet.Filter的MyCORSFilter实现是链中的第一个。希望这可以帮到你。


这个对我来说是有效的。唯一的问题是它在同一个请求中被调用多次。 - Mohit Kanwar
不返回 CSS/图标等内容,因为它们托管在不同的服务器上,但是让我检查。 - Mohit Kanwar
1
@MohitKanwar 请尝试使用OncePerRequestFilter,公共类CustomFIlter继承自OncePerRequestFilter。 - user9578753
这对我没有用,但这个可以:https://dev59.com/LloV5IYBdhLWcg3wA66x#36821971 - Tomas Lukac

8

无需添加任何额外的过滤器WebMvcConfigurer。主要问题是'Access-Control-Allow-Origin'在标头中不存在,因为corsConfigurationSource没有添加必要的配置以获取相关的CORS响应标头。因此,在配置CorsConfigurationSource时必须添加以下缺失的配置:

configuration.addAllowedOrigin("*");
configuration.addAllowedHeader("*");
configuration.addAllowedMethod("*");

我们需要按照以下方式配置 CorsConfigurationSource 来处理跨域问题。

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
            .cors().configurationSource(corsConfigurationSource())
                .and()
                 .....
  }

 @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        configuration.setAllowCredentials(true);
        //the below three lines will add the relevant CORS response headers
        configuration.addAllowedOrigin("*");
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }


如果在Spring Boot 2.4.0及以上版本中使用以下组合时遇到CORS问题,请参考答案

CorsConfigurationSource#setAllowedOrigins的值为*

CorsConfigurationSource#setAllowCredentials的值为true


为什么在 setAllowedOrigins(Arrays.asList("*")) 之后还要执行 addAllowedOrigin("*") - GalAbra
1
是的,您可以删除以下的 addAllowedOrigin("*"),因为我们已经添加了 setAllowedOrigins(Arrays.asList("*")),我只是为了说明可以添加多个选项来添加来源。 - Prasanth Rajendran
但是,如果您删除这些重复的行,则与 OP 的问题中的代码相同,对吧? 我不明白,我已经按照您说的配置了我的设置,但仍然出现“没有允许 Origin 标头”的预检错误... - Boommeister
当allowCredentials为true时,allowedOrigins不能包含特殊值"*",因为它不能设置在"Access-Control-Allow-Origin"响应头中。要允许凭据访问一组源,请明确列出它们,或考虑使用"allowedOriginPatterns"代替。 - undefined

7

请看Spring提供的这份指南:

https://spring.io/guides/gs/rest-service-cors/

在Spring Boot中,有几种方法来添加CORS支持。

使用全局配置:

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurerAdapter() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/greeting-javaconfig").allowedOrigins("http://localhost:9000");
        }
    };
}

使用@CrossOrigin注释:

@CrossOrigin(origins = "http://localhost:9000")
@GetMapping("/greeting")
public Greeting greeting(@RequestParam(required=false, defaultValue="World") String name) {
    System.out.println("==== in greeting ====");
    return new Greeting(counter.incrementAndGet(), String.format(template, name));
}

4

好的,我意识到这已经过时了。如果你在Baeldung上查看,它有如何使用更新的WebMvcConfigurer进行操作的方法:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

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

你不必使用 @EnableWebMvc,我认为。如果你使用了它,Spring Boot 将无法自动配置 MVC。 - Paulo van Goethe
此外,如果您要允许所有来源,那么CORS的意义是什么,这是您的代码所表达的。 - Paulo van Goethe
您关于允许所有来源的观点是正确的,这是我用于测试的示例代码。 - Mohit Kanwar
好的,我想可能是这样。 - Paulo van Goethe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接