CORS问题-预检请求的响应未通过访问控制检查

3
我正在开发使用Spring Boot作为后端的ReactJS前端。 我试图从前端调用端点,如下所示:
testOktaTokenAtRest(data) {
  var oauth=JSON.parse(localStorage.getItem('okta-token-storage'))
  console.log("toekn is: ==>  "+oauth.accessToken.tokenType + 
  oauth.accessToken.accessToken)
  console.log("toekn received from action is inside this obj: ",data)
  var searchCriteria = JSON.stringify(data.data)
  console.log("searchCriteria data -------: " , searchCriteria)

 let _headerForSearch={
    auth : 'Bearer ' + oauth.accessToken.accessToken 
  }
  $.ajax({
    method: "post",
    url: "http://localhost:8000/ckcapp/api/posttest",
    contentType: "application/json",
    dataType: "json",
    data:searchCriteria,
    beforeSend: function (xhr) {
      xhr.setRequestHeader("Authorization", _headerForSearch.auth);
    },
    success: function(response) {

      console.log("response from okta enabled get api is: ",response)
    },
    error: function(xhr, status, error) {
      console.log("error from okta enabled get api is: ",xhr.responseText 
     + " " +status + " " + error );
    }
  });


  }

当我发出请求时,我收到以下错误信息:-

XMLHttpRequest访问 'http://localhost:8000/ckcapp/api/posttest' 来自源 'http://localhost:3000' 已被CORS策略阻止: 对预检请求的响应未通过访问控制检查:所请求的资源上不存在 'Access-Control-Allow-Origin' 标头。

我的spring-boot应用程序具有以下配置:
CORSFilter
    public class CORSFilter implements Filter {


    private static final String ONE_HOUR = "3600";

      @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", 
    "http://localhost:3000");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, 
    GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", ONE_HOUR);
        response.setHeader("Access-Control-Request-Headers", 
    "authorization,content-type");
        response.setHeader("Access-Control-Allow-Headers", "X-Requested- 
    With,Origin,Content-Type, Accept, x-device-user-agent, Content-Type");

        if (req instanceof HttpServletRequest) {
           HttpServletRequest httpServletRequest = (HttpServletRequest) 
    req;
           if (httpServletRequest.getHeader(HttpHeaders.ORIGIN) != null
              && 
      httpServletRequest.getMethod().equals(HttpMethod.OPTIONS.name())
              && 
    httpServletRequest.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) 
    != 
    null) {

              return;
           }
        }
        chain.doFilter(req, res);
      }

      @Override
      public void destroy() {
      } 
    }

我正在调用端点:

 @RestController
    @CrossOrigin(origins = "http://localhost:3000")
    public class CkcOktaController {
        @PostMapping("/api/posttest")
    @PreAuthorize("hasAuthority('SCOPE_email')")
    public String setString(@RequestBody CustomerDetailsNew 
        customerDetails) {
        System.out.println("In post method ");
        System.out.println("text :" + customerDetails.toString());
        System.out.println("text :" + customerDetails.getEntityId());
        return "Success";
    }
    }

我觉得我缺少一些配置。
该应用程序受OKTA保护。

我认为你需要处理预检请求。https://blog.morethancode.dev/killing-cors-preflight-requests-on-a-react-spa/ - RSingh
2个回答

11

通常我使用bean来配置CORS设置。这是来自最近的博客文章

@Bean
public FilterRegistrationBean<CorsFilter> simpleCorsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.setAllowedOrigins(Collections.singletonList("*"));
    config.setAllowedMethods(Collections.singletonList("*"));
    config.setAllowedHeaders(Collections.singletonList("*"));
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
    bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return bean;
}

这个基于过滤器的配置对我来说完美地运作了。有人能帮我理解一下,为什么另一种配置方式,即添加@Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("*").allowCredentials(true).maxAge(3600); } }没有起作用吗?这种方法在大多数相关讨论中都被建议,但对我来说并没有起作用。 - Naveen Kumar
当我尝试时,遇到了以下问题:java.lang.IllegalArgumentException: 当allowCredentials为true时,allowedOrigins不能包含特殊值“*”,因为它不能设置在“Access-Control-Allow-Origin”响应标头上。要允许凭据访问一组来源,请明确列出它们或考虑改用“allowedOriginPatterns”。 - Rahman Malik
1
使用最新版本的Spring Boot,如果您想要通配符支持,则必须使用allowedOriginPatterns("*")。或者使用allowedPatterns()显式定义。您还可以在YAML中定义,例如:allowed-origins: "http://localhost:8100,http://localhost:9000" - Matt Raible

7

我正在使用React和Spring JWT,遇到了与CORS策略相关的类似问题。

在我的SecurityConfigurer类中添加了http.cors()以解决该问题。

@EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().......
    }
}

控制器

@CrossOrigin(origins = {"http://localhost:3000"})
@RestController

2
尝试了不同线程中提出的各种解决方案,但只有这个对我有帮助。谢谢! - Bogdan Kobylynskyi
这花了相当长的时间来弄清楚,谢谢!我明白应该实施CSRF,但对我们来说稍后再来。 可以确认在Spring 3.0更改后,WebSecurityConfigurerAdapter被弃用,SecurityFilterChain方法取而代之。 - undefined

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