【问题标题】:AngularJS authentication with Spring Security CORS issues带有 Spring Security CORS 问题的 AngularJS 身份验证
【发布时间】:2016-11-02 11:42:45
【问题描述】:

我正在使用https://spring.io/guides/tutorials/spring-security-and-angular-js 上的教程将 AngularJS 应用程序连接到 Spring Security 后端进行身份验证。

当我尝试登录时(用户名和密码已存在于后端),我在浏览器控制台中收到以下错误(我在 Chrome、Firefox 和 IE 中测试我的应用程序,它们都给了我同样的错误) .

错误是:

 XMLHttpRequest cannot load http://SERVER_URL:4444/test/user. 
Response to preflight request doesn't pass access control 

        check: No 'Access-Control-Allow-Origin' header is present on the requested resource. 

         Origin 'http://localhost:3000' is therefore not allowed access. 
            The response had HTTP status code 401.

代码:

var auth = angular.module("Admin");

authService.service("AuthService", function($http, $rootScope){

    this.login = function(credentials){
        var headers = credentials ? {authorization: "Basic " + btoa(credentials.username + ":" + credentials.password)} : {};

        $http.get("http://SERVER_URL:4444/test/user",{headers:headers})
            .then(function(response){
                console.log("success");
                $rootScope.authenticated = true;
        }, function(){
                console.log("failed");
                $rootScope.authenticated = false;
            });


    };




});

当我在浏览器中访问相同的链接时,我得到了验证框,我输入了用户名和密码,我可以看到结果。但是我不明白为什么我不能通过 $http() 成功访问同一个链接。

正确的做法是什么?我已经阅读了许多帖子和问答,但没有一个能解决问题。我只是不明白发生了什么。

【问题讨论】:

  • "当我在浏览器中访问同一个链接时......我可以看到结果。但我不明白为什么我不能通过 $http() 访问同一个链接成功” 所以你使用CORS这个词知道它的意思。顺便说一句,您链接到的教程解释了如何添加对 CORS 的支持,所以我想知道您为什么“花了几天时间在谷歌上搜索”

标签: javascript java angularjs spring spring-mvc


【解决方案1】:

您需要在后端的 Spring Security 配置中注册一个 CORS 过滤器,以允许您的 Angular 应用程序的来源访问后端,因为它正在发出跨域请求(它不是来自同一主机和端口) :

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

  @Bean
  public CorsFilter corsFilter() {
    final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration corsConfiguration = new CorsConfiguration();
    corsConfiguration.setAllowCredentials(true);
    corsConfiguration.addAllowedOrigin("*");
    corsConfiguration.addAllowedHeader("*");
    corsConfiguration.addAllowedMethod("*");
    urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
    return new CorsFilter(urlBasedCorsConfigurationSource);
  }

}

或者,如果您使用的是不支持CorsConfiguration 的旧版 Spring Security,您可以通过实现自定义过滤器并将其注入您的过滤器链来完成同样的事情:

@Component
public class CorsFilter implements Filter {

  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletResponse response = (HttpServletResponse) res;
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "*");
    response.setHeader("Access-Control-Allow-Headers", "*");
    chain.doFilter(req, res);
  }

  public void init(FilterConfig filterConfig) {}

  public void destroy() {}

}

【讨论】:

  • 感谢您的快速回答。但是为什么当我直接从浏览器访问相同的地址时它会起作用?
  • 因为 CORS 旨在防止跨站点请求,而不是来自浏览器的请求。你可以在这里阅读更多信息:html5rocks.com/en/tutorials/cors
  • 我们现在的问题是我们已经使用这里描述的控制器配置了 CORS::spring.io/blog/2015/06/08/cors-support-in-spring-framework。为什么我们必须添加过滤器呢?你能解释一下吗。在正常情况下它必须工作,但它不工作。
  • 有几个不同的可能问题,可能是由于某种原因,您的依赖项之一强制使用 4.2 之前的 Spring Framework 版本进行编译;做一个依赖树来确定是否是这种情况。它也可能与缺少 @EnableWebMvc 注释配置类有关,请参见此处:jira.spring.io/browse/SPR-13857 我以前没有使用过 CORS 注释,所以我不确定为什么这些注释不起作用,但我有大多数解决方法在他们看来失败只涉及实现过滤器。
【解决方案2】:

默认情况下,浏览器已经实现了安全策略,不执行从不同域加载的脚本。即使来自同一主机和不同端口,它也不会允许,因为它违反了跨域策略。

有很多方法可以解决这个问题。

最好的方法是在服务器上启用 CORS,这样从第一个响应开始,服务器就会指示浏览器允许跨域。请参阅链接以获取更多信息http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server

【讨论】:

  • 根据我的理解,当你刚输入url和从你的脚本中调用url是浏览器触发的两种不同类型的请求。当你使用脚本发出请求时,它的 XMLHttpRequest 类型,如果你只是将它输入到浏览器的地址栏中,它可能是一个 http 请求
猜你喜欢
  • 2019-04-08
  • 1970-01-01
  • 2016-05-29
  • 1970-01-01
  • 2014-05-11
  • 2013-05-13
  • 2017-03-25
  • 2016-12-22
  • 2018-10-05
相关资源
最近更新 更多