如何修复 Spring Boot + Vue 应用程序中损坏的 CORS?

Posted

技术标签:

【中文标题】如何修复 Spring Boot + Vue 应用程序中损坏的 CORS?【英文标题】:How I can fix broken CORS In Spring Boot + Vue app? 【发布时间】:2020-11-06 15:33:54 【问题描述】:

在我的问题中,后端有 Spring Boot 应用程序(使用 Spotify API),前端有 Vue 应用程序。我在 localhost:8080 上使用服务器,在 localhost:8081 上使用前端。我想通过 axios 将我的前端连接到我的后端,我尝试了一切,但仍然出现 CORS 错误。

当我调用测试 GET 端点 /getList() 时,我得到了

Access to XMLHttpRequest at 'http://localhost:8080/getList' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

当我尝试调用 POST /findTracks() 时,我得到了:

Access to XMLHttpRequest at 'http://localhost:8080/findTracks' from origin 'http://localhost:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.

而且我已经尝试了所有方法(如您在下面的代码中所见)。

第一:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class CorsConfiguration implements WebMvcConfigurer 
    @Override
    public void addCorsMappings(CorsRegistry registry)
        registry.addMapping("/**").allowedHeaders("*").allowedMethods("*");
     //even with .allowedOrgins("http://localhost:8081");

然后在Controller类中:

@CrossOrigin(origins = "*", allowedHeaders = "*")
@RestController
public class SpotifyApiController 

    @CrossOrigin(origins = "*", allowedHeaders = "*")
    @RequestMapping(value = "/getList", method = RequestMethod.GET)
    public List<String> getList() 
        ArrayList<String> a = new ArrayList<>();
        a.add("dwa");
        a.add("trzy");
        return a;
    

    @RequestMapping(value = "/findTracks",
            method = RequestMethod.POST,
            consumes = "application/json",
            produces = "application/json")
    public List<Track> getTracksForTitles(@RequestBody TrackWrapper userTracks, TrackService tracksService, OAuth2Authentication details) 
        return tracksService.generateTracksDetails(getActiveToken(details), userTracks);
    

然后在 Vue 中:

import axios from 'axios';
const SERVER_URL = 'http://localhost:8080'

const instance = axios.create(
    baseURL: SERVER_URL,
    timeout: 1000
);

export default
    findTracksInSpotify:(jsonObject)=>instance.post('/findTracks',
    userTracks: jsonObject.userTracks,
    headers:
        'Content-Type': 'application/json',     
    
).then(() => function(data)
    return JSON.parse(data)
),
getList:()=>instance.get('/getList',
    transformResponse:[function(data)
        return JSON.parse(data)
    ]
),

如果需要,还有我的 Spring Security 课程:

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.web.context.request.RequestContextListener;


@Configuration
@EnableOAuth2Sso
@EnableWebSecurity
public class OAuth2Configuration extends WebSecurityConfigurerAdapter 

@Override
protected void configure(HttpSecurity http) throws Exception 
    http
            .csrf().disable()
            .antMatcher("/**")
            .authorizeRequests()
            .antMatchers("/", "/login**")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and().logout().logoutSuccessUrl("/").permitAll();

@Bean
public RequestContextListener requestContextListener() 
    return new RequestContextListener();


我什至安装了 chrome 扩展,但它也不起作用。

你能告诉我我做错了什么吗?

【问题讨论】:

【参考方案1】:

有一个 RestConfiguration corsfilter 的示例。您可以将以下 bean 添加到您的代码中:

@CrossOrigin
@Configuration
public class RestConfiguration 

  @Bean
  public FilterRegistrationBean corsFilter() 

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("DELETE");
    config.addAllowedMethod("PATCH");

    source.registerCorsConfiguration("/**", config);
    final FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
  

【讨论】:

这在不同的测试项目中与通常的 cors 配置一样工作,但在这个项目中它不起作用。我想也许 OAuth2 Config 会阻止 Cors?【参考方案2】:

我认为你不需要CorsConfiguration这个类。

您也不需要使用CrossOrigin 注释SpotifyApiController

理想情况下,CORS 的配置应该放在安全配置中。类似的东西(OAuth2Configuration):

import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;

@Configuration
@EnableOAuth2Sso
@EnableWebSecurity
public class OAuth2Configuration extends WebSecurityConfigurerAdapter 

@Override
protected void configure(HttpSecurity http) throws Exception 
  // The configuration that you needed

  // If preflight requests are redirected by OAuth conf, you can try adding:
  // .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

  // CORS configuration

  // This value must be parameterized according to your application needs 
  final String corsOrigin="http://localhost:8081";
  // The idea is to insert the CORS filter before the filter injected by
  // the @EnableOAuth2Sso annotation
  http.addFilterBefore(new CorsFilter(corsConfigurationSource(corsOrigin)), AbstractPreAuthenticatedProcessingFilter.class);


private CorsConfigurationSource corsConfigurationSource(String corsOrigin) 
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList(corsOrigin));
    configuration.setAllowedMethods(Arrays.asList("GET","POST","HEAD","OPTIONS","PUT","PATCH","DELETE"));
    configuration.setMaxAge(10L);
    configuration.setAllowCredentials(true);
    configuration.setAllowedHeaders(Arrays.asList("Accept","Access-Control-Request-Method","Access-Control-Request-Headers",
      "Accept-Language","Authorization","Content-Type","Request-Name","Request-Surname","Origin","X-Request-AppVersion",
      "X-Request-OsVersion", "X-Request-Device", "X-Requested-With"));
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;



【讨论】:

也不行,我想我必须创建授权服务器和资源服务器。这很奇怪,因为整个 cors 的东西都来自邮递员,而不是前端。 这是因为当您使用 Postman 或 cUrl 时,您会直接调用 API。简而言之,CORS 与在原始域外通过 XMLHttpRequets API 调用有关,以减少跨域 HTTP 请求的可能性。我编辑了答案以重新定义 Spring Security 过滤器链。您也可以尝试允许甚至忽略 OPTIONS(预检)请求的安全性。我认为您不必创建授权或资源服务器。通过使用 EnableOAuth2Sso 注释,您正在创建一个 OAuth 客户端。 这很奇怪,所有这些解决方案都可以在 .antMatchers("/", "/login**", "/findTracks") .permitAll() 添加例如 "/findTracks" , "/addSongs" 等。这样对吗,不应该授权吗? 当然不行,应该认证。你试过编辑答案的代码吗?还允许选项?请在 CorsFilter 和 OAuth2ClientAuthenticationProcessingFilter 中设置断点,看看会发生什么,首先调用哪个过滤器。 是的,我试过了,但它抛出:通过工厂方法的 Bean 实例化失败;嵌套异常是 org.springframework.beans.BeanInstantiationException:无法实例化 [javax.servlet.Filter]:工厂方法“springSecurityFilterChain”抛出异常;嵌套异常是 java.lang.IllegalArgumentException: 未注册过滤器类 org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter 后无法注册【参考方案3】:
@Override
    protected void configure(HttpSecurity http) throws Exception 
        http.cors().configurationSource(request -> 
            CorsConfiguration cors = new CorsConfiguration();
            cors.setAllowedOrigins(
                    Lists.newArrayList("*"));
            cors.setAllowedMethods(Lists.newArrayList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
            cors.setAllowedHeaders(Lists.newArrayList("*"));
            return cors;
        ).and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()
                .antMatchers("")
                .permitAll().and()
                .addFilterBefore(setLoginProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
    

【讨论】:

【参考方案4】:

您是否尝试在控制器类和存储库类上使用 @CrossOrigin(origins="http://localhost:8081")?

还结合它:尝试在主 SpringBoot Application 类中添加 WebConfigurer Bean 并使用 @CrossOrigin(origins="http://localhost:8081") 进行注释

@Bean
    public WebMvcConfigurer corsConfigurer() 
        return new WebMvcConfigurer() 
            @Override
            public void addCorsMappings(CorsRegistry registry) 
                System.out.println("here");
                registry.addMapping("/**").allowedOrigins("http://localhost:8081").allowedMethods("PUT", "DELETE" )
                .allowedHeaders("header1", "header2", "header3")
                .exposedHeaders("header1", "header2")
                .allowCredentials(false).maxAge(3600);;
            
        ;
    

请也访问此链接以获取 enabling CORS in your application server side,并根据您的配置检查您可以使用哪种 CORS 方法。

【讨论】:

以上是关于如何修复 Spring Boot + Vue 应用程序中损坏的 CORS?的主要内容,如果未能解决你的问题,请参考以下文章

如何修复 Spring Boot 数据 jpa UnsatisfiedDependencyException

如何在Spring-boot中修复错误“Whitelabel错误页面”

如何修复不兼容的外键约束spring boot

如何修复 £ 符号前的特殊字符 - 399 英镑 - Spring Boot json

如何验证我正在使用的 Spring Boot 版本中是不是有 Spring 功能/Bug 修复?

重新打包 Spring Boot Jar 时如何修复压缩错误