春季启动:CORS处理GET请求,但不处理POST请求

时间:2020-10-31 12:51:58

标签: java spring spring-boot cors

问题:

CORS正在处理方法参数中没有@AuthenticatedPrincipal的GET请求。

我正在使用

  • OKTA作为我的身份验证服务器。
  • Spring REST控制器
  • Spring数据(CrudRepository)

由于某种原因,我每次都会遇到此错误,我正在发出方法参数中带有@AuthenticatedPrincipal的POST,PUT或不安全请求,但它适用于GET请求:

Error code

我已经使用Spring Boot阅读了有关CORS设置的所有可能的Stackoverflow问题,并像这样配置了我的CORS,但无济于事:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()
                .csrf().disable()
//                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
//                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers( "/courses", "/testing/*").permitAll()
                .anyRequest().authenticated().and()
                .oauth2Login().and()
                .oauth2ResourceServer().jwt();
        http.headers().frameOptions().disable();
    }

//    @Bean
//    CorsConfigurationSource corsConfigurationSource() {
//        CorsConfiguration configuration = new CorsConfiguration();
//        configuration.setAllowedOrigins(Arrays.asList("*"));
//        configuration.setAllowedMethods(Arrays.asList("POST", "GET", "PUT", "OPTIONS", "HEAD", "DELETE"));
//        configuration.setAllowedHeaders(Arrays.asList("Content-Type"));
//        configuration.setExposedHeaders(Arrays.asList("Authorization", "Link", "X-Total-Count", "Access-Control-Allow-Headers"));
//        configuration.setAllowCredentials(true);
//        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//        source.registerCorsConfiguration("/**", configuration);
//        return source;
//    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration().applyPermitDefaultValues();
        configuration.setAllowedOrigins(ImmutableList.of("*"));
        configuration.setAllowedMethods(ImmutableList.of("OPTIONS", "HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
        // setAllowCredentials(true) is important, otherwise:
        // The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the
        // request's credentials mode is 'include'.
        configuration.setAllowCredentials(true);
        // setAllowedHeaders is important! Without it, OPTIONS preflight request
        // will fail with 403 Invalid CORS request
        configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));

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


我的控制器

@CrossOrigin
@RestController
@RequestMapping(EndPoints.TEST_PATH)
public class TestController {

    private final TestService tService;

    @Autowired
    public TestController(TestService tService) {
        this.tService = tService;
    }

    @PostMapping(path="/create")
    public ResponseEntity<String> addNewTest(@Valid @NonNull @RequestBody TestDTO data,
                                               @AuthenticationPrincipal Jwt principal){

        tokenUserEmail =  token.getClaimAsString("sub");
        tokenUid = token.getClaimAsString("uid");
        tokenFullName = token.getClaimAsString("firstName") + " "
                + token.getClaimAsString("lastName");
        
        TestEntity testEntity = new TestEntity();
        testEntity.setName(tokenFullName);
        testEntity.setGrade(data.grade);
        testEntity.setNumber(data.number);

        tService.addNewTest(testEntity);
        
    }
    

}

我已经用尽了每个可能的Stackoverflow问题,创建了WebMvcConfigurerAdapter(),设置和取消设置了@CrossOrigin。在这一点上,我不知道我还能做什么...任何人都知道我该如何解决??

2 个答案:

答案 0 :(得分:-1)

在CORS浏览器中,始终将简单的跨域请求(例如GET请求)发送到服务器。但是浏览器会检查服务器的响应标头(Access-Control-Allow-Origin),服务器是否允许跨域请求。这就是您的 GET 请求访问服务器的原因。但是 POST,PUT,DELETE 浏览器之类的非简单请求无法使请求进入服务器。而是,浏览器将预检请求发送到服务器,以检查是否允许跨域请求。如果来自服务器的响应包含支持跨域请求的标头,则只有浏览器才会执行实际的请求。此飞行前请求是作为 OPTIONS 请求发送的。这就是为什么您的错误说对预检请求的响应没有通过的原因。 启用S​​pring安全性后,Spring Security会针对未经身份验证的用户阻止所有预检请求。要允许通过预检请求,我们必须在安全配置中进行配置。

enter image description here

在csrf()之后删除disable()。然后在方法顶部添加 @CrossOrigin 批注。您也可以在注解中提及域。 @CrossOrigin(“ http:// localhost:3000”)

这是您唯一要做的事情。

答案 1 :(得分:-1)

预检请求是浏览器在实际请求之前发送的一个小请求。它包含以下信息:使用哪种HTTP方法,以及是否存在任何自定义的 HTTP标头(例如Access-Control-Allow-Methods)。

执行POST操作时,有2个步骤。第一个请求是OPTIONS,因此是 preflight 请求。完成 preflight 后,您的浏览器就会知道允许或拒绝哪些请求类型。

在您的情况下,问题在于,当后端需要1个呼叫时,您正在发送2个(预检+实际请求)

要解决此问题,您必须告诉您的后端在OPTIONS请求到达时做出响应,并确定

免责声明::我没有尝试使用您配置 cors CorsConfigurationSource )的方式进行尝试。但是,让我用一个简单的滤豆展示它

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

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        final 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", ""Authorization, Cache-Control, Content-Type"");
        response.setHeader("Access-Control-Max-Age", "3600");
        
        //SEND OK or validate
        if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void destroy() {
        //
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        //
    }
}
相关问题