【问题标题】:CORS policy conflict in Spring bootSpring Boot 中的 CORS 策略冲突
【发布时间】:2019-11-07 14:46:36
【问题描述】:

我是 Spring Boot 新手,我使用 Spring Boot 实现了一些基本的 REST API。当我尝试使用 react 调用这些 api 时,调用某些 CORS 策略时出错。然后我找到了解决该问题的方法,并且我的所有 api 端点都可以正常工作,除了登录 api 调用。我得到同样的错误调用:

这是我的网络安全 java 类。

@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {

    private final UserService userDetailsService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    public WebSecurity(UserService userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.userDetailsService = userDetailsService;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.csrf().disable().authorizeRequests().antMatchers(HttpMethod.POST, SecurityConstants.SIGN_UP_URL)
                .permitAll().anyRequest().authenticated().and().cors().and().addFilter(getAuthenticationFilter())
                .addFilter(new AuthorizationFilter(authenticationManager())).sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

    public AuthenticationFilter getAuthenticationFilter() throws Exception {
        final AuthenticationFilter filter = new AuthenticationFilter(authenticationManager());
        filter.setFilterProcessesUrl("/users/login");
        return filter;
    }
}

这是我的示例控制器类。

@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    UserService userService;

    @CrossOrigin
    @GetMapping(path = "/{id}", 
            produces = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE })
    public UserRest getUser(@PathVariable String id) {

        UserRest returnValue = new UserRest();

        UserDto userDto = userService.getUserByUserId(id);
        BeanUtils.copyProperties(userDto, returnValue);

        return returnValue;
    }

    @CrossOrigin
    @PostMapping(
            consumes = { MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE }, 
            produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE })
    public UserRest createUser(@RequestBody UserDetailsRequestModel userDetails) {

        UserRest returnValue = new UserRest();

        UserDto userDto = new UserDto();
        BeanUtils.copyProperties(userDetails, userDto);

        UserDto createUser = userService.createUser(userDto);
        BeanUtils.copyProperties(createUser, returnValue);

        return returnValue;
    }
}

我被这个问题困住了,我真的需要一些帮助。我已经尝试过 stackoverflow 中给出的一些与我的问题类似的答案。但这并没有解决我的问题。 Mt spring boot 版本是2.1.4

【问题讨论】:

    标签: java spring spring-boot cors


    【解决方案1】:

    试试这个,

    @Configuration
    public class WebConfiguration implements WebMvcConfigurer {
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedMethods("*");
        }
    }
    

    更新

    你也可以这样做,

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

    【讨论】:

    • 谢谢@Avi。但是我的问题解决了。顺便谢谢
    • 解决方案是什么?
    【解决方案2】:

    您正面临这个问题,因为您已经允许后端从端口 8080 进行 cors,但您的反应在本地端口 3000 中启动。因此,springboot 不会接受来自不同端口地址的请求。

    方法一:

    您可以通过使用以下注释来解决这个问题:

    @CrossOrigin(origins = "http://localhost:3000", maxAge = 3600)
    

    由于您使用的是 springboot ,您还可以使用以下全局配置来定义哪些所有域都可以访问您的后端。

    @Configuration
    public class MyConfiguration {
    
        @Bean
        public WebMvcConfigurer corsConfigurer() {
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("http://localhost:3000")
                        .allowedMethods("PUT", "DELETE", "GET", "POST") //or allow all as you like
                        .allowedHeaders("header1", "header2", "header3")
                        .exposedHeaders("header1", "header2")
                        .allowCredentials(false).maxAge(3600);
                 }
            };
        }
    }
    

    如果您仍然遇到问题,可能是因为 Spring Security 没有在您的 响应标头中添加像 Access-Control-Allow-Origin 这样的 CORS 标头。在这种情况下,您可以定义一个自定义 CORS 过滤器并将其添加到 spring 安全性,以便为所有 spring 安全性端点设置 CORS 响应标头。您可以像这样创建一个过滤器 bean:

    public class CorsFilter implements Filter {
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            HttpServletRequest request= (HttpServletRequest) servletRequest;
    
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS");
            response.setHeader("Access-Control-Allow-Headers", "*");
            response.setHeader("Access-Control-Allow-Credentials", true);
            response.setHeader("Access-Control-Max-Age", 180);
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    方法二:

    由于您使用的是 spring security,您还可以添加 CORS 配置以及 spring security,例如:

    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.cors().and()
                //other configurations that you want
        }
    
        @Bean
        CorsConfigurationSource corsConfigurationSource()
        {
            CorsConfiguration configuration = new CorsConfiguration();
            configuration.setAllowedOrigins(Arrays.asList("*"));
            //or any domain that you want to restrict to 
            configuration.setAllowedMethods(Arrays.asList("GET","POST"));
            //Add the method support as you like
            UrlBasedCorsConfigurationSource source = new     UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", configuration);
            return source;
        }
    } 
    

    据我所知,即使您在方法 1 中提供 CORS 配置,Spring security 也会占用它。但是,在 Spring 文档中,他们也提供了这种向 Spring Security 注册 CORS 的方式。

    在您附加的 控制台日志 中,据说由于返回的 http 状态不正常,飞行前检查失败。所以,您可以尝试像方法 2 一样注册 cors 并使用过滤器添加以便在响应中正确添加标题。访问登录页面时,Springboot 正在阻止飞行前检查。您需要使用 spring security 正确设置您的 cors,以允许从不同的端口访问登录页面。

    确认您的登录页面 /login 映射允许 CORS

    官方Doc 参考Doc

    【讨论】:

    • 我尝试了所有方法。但结果是一样的。只有登录api无法通过react访问
    • 在您附加的控制台日志中,据说由于返回的 http 状态不正常,飞行前检查失败。所以,您可以尝试像方法 2 一样注册 cors 并添加一个过滤器标头作为响应正确添加。访问登录页面时,Springboot 正在阻止飞行前检查。您需要使用 spring security 正确设置您的 cors,以允许从不同的端口访问登录页面。
    • 然后它说:对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。
    • 在 springboot 响应头中设置以下内容,它应该可以工作:Access-Control-Allow-Origin
    • 在我上面的回答中,我提供了如何创建自定义 CORS 过滤器,只需在您的 spring 安全配置中注册 CORS 过滤器。在这种情况下,某些浏览器(如 edge)有时不会将 * 识别为来源尝试将localhost:3000 添加到您的来源列表。
    猜你喜欢
    • 2021-12-19
    • 2021-03-01
    • 2021-08-14
    • 2019-08-15
    • 2021-10-13
    • 1970-01-01
    • 2021-01-23
    • 1970-01-01
    • 2021-11-14
    相关资源
    最近更新 更多