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

时间:2017-03-23 09:53:56

标签: javascript angularjs node.js spring google-chrome

我有一个RESTfull后端实现了在localhost上运行的Spring安全性:8080,一个Login过滤器响应登录请求并在头文件中放置了一个令牌,我甚至没有实现一个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)
    …

前端是Angularjs Nodejs NPM Bower项目,在localhost:8000上运行静态http服务器。在前端,我按如下方式发出一个简单的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)Spring Security禁用csfr

2)Spring Security Permit all

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:由于输入结束而没有要映射的内容

春天的安全部门会对此进行聊天,拒绝访问。

我还试图将前端服务器移到8000(4200,7000等)的其他端口上但没有成功。

2 个答案:

答案 0 :(得分:1)

您需要在春季启用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.
    }
}

这使得整个应用程序的角色成为可能。您还可以更具体地使用允许特定标头和方法的映射。

@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/

答案 1 :(得分:0)

之前我使用过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)