繁体   English   中英

Chrome,Safari和Firefox上的CORS POST请求失败

[英]CORS POST request fails on Chrome, Safari and Firefox

我有一个在localhost:8080上运行的具有Spring Security的RESTfull后端,登录过滤器使用放置在标题中的令牌响应登录请求,我什至没有实现Endpoint方法,这全部由Spring Security魔术完成通过以下代码行:

  protected void configure(HttpSecurity http) throws Exception {
        // disable caching
        http.headers().cacheControl();

        http.csrf().disable() // disable csrf for our requests.
            .authorizeRequests()
            .antMatchers("/").permitAll()
            .antMatchers("/login").permitAll()
            .anyRequest().authenticated()
            .and()
            // We filter the api/login requests
            .addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
    …

前端是一个在localhost:8000上运行静态http服务器的Angularjs Nodejs NPM Bower项目。 在前端,我发出一个简单的POST请求,如下所示:

   $scope.login = function () {

    var data = {
        "username":$scope.username,
        "password":$scope.password
    }

    $http({
        url: baseUrl,
        method: "POST",
        data: data
    }).then(function (response) {
        console.log("###### SUCCESS #####");
        var headers = response.headers();
        console.log("headers: "+JSON.stringify(headers));
        var token = headers.authorization.split(" ")[1];
        console.log("token: "+token);
        $http.defaults.headers.common['Authorization'] = token;
        $location.path("/view1");

    }, function (responseData) {
        // called asynchronously if an error occurs
        // or server returns responseData with an error status.
        console.log("###### FAIL #####");
        console.log("Response: "+JSON.stringify(responseData));
        $window.alert("Failed to Login");
    });

这就像IE中的一种魅力一样(也适用于curl,wget和python请求),但在Chrome和Safary上却失败了。 我知道这些浏览器正在阻止CORS POST,从而使该请求一到达后端就为空,实际上,当我从后端注销请求时,我看不到任何数据。 我尝试了以下所有可能的组合:

前端侧:

1)$ http(方法:POST)

2)$ http.post(

3)添加标志:Access-Control-Allow-Origin,Access-Control-Expose等。

4)添加所有可能的标头组合:'Content-Type':'application /

浏览器端:

1)使用标志启动chrome:--disable-web-security

2)安装Chrome扩展程序CORS

后端:

1)春季安全禁用csfr

2)春季安全许可证全部

3)Spring Security HttpMethod.OPTION

没事,NHOTING对我有用!

有什么我想念的吗?

还有其他发送POST请求的方法吗?

编辑

如前所述,我将类修改如下:

WebSecurityConfig:

        .antMatchers("/login").permitAll()
        .anyRequest().authenticated()
        .and()
        // We filter the api/login requests
        .addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
        .addFilterBefore(new CORSFilter(), BasicAuthenticationFilter.class)

并实现了CORSFilter作为建议。

我还根据建议添加了WebConfig类:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("http://localhost:8000")
        .allowedMethods("PUT", "POST");
    }
}

由于字符串为空,因此登录过滤器将抛出:

com.fasterxml.jackson.databind.JsonMappingException:由于输入结束,没有要映射的内容

Spring Security将拒绝访问此消息。

我还尝试将前端服务器移至其他端口,然后移至8000(4200、7000等),但均未成功。

您需要在春季启用Cors支持。 在您的WebConfig中,您可以覆盖addCorsMappings

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("http://localhost:4200");  //url of where angular is running.
    }
}

这使得整个应用程序都可以使用cors。 您还可以使用允许特定的标头和方法的映射来更具体。

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/api/**")
            .allowedOrigins("http://domain2.com")
            .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3");
}

您还可以在类和方法级别允许用户@CrossOrgin

@CrossOrigin(origin = "http://domain2.com",
             maxAge = 3600)
public class ApiController {

}

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cors.html

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

我以前使用过CORS过滤器,并且效果很好:

public class CORSFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.addHeader("Access-Control-Allow-Origin", "*");

        if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {

            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
            response.addHeader("Access-Control-Allow-Headers", "Content-Type");
            response.addHeader("Access-Control-Max-Age", "1");
        }

        filterChain.doFilter(request, response);
    }

}

然后将其添加到您的配置中:

.addFilterBefore(new CORSFilter()), BasicAuthenticationFilter.class)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM