JQuery跨域基本认证调用

Posted

技术标签:

【中文标题】JQuery跨域基本认证调用【英文标题】:JQuery cross domain basic auth call 【发布时间】:2012-04-21 06:12:33 【问题描述】:

我已经使用 Spring MVC 构建了一个 REST API 后端,并使用 Spring Security 进行基本身份验证。

我想从 javascript 客户端对 REST API 进行跨域 ajax 调用。我不想使用 JSONP,因为我不想局限于 GET 调用。我使用 CORS,并且在服务器端放置了正确的标头。

假设我的 REST API 在域 localhost:8087 上,而我的客户端在 localhost:8086 上,这是跨域调用。

在我的 Javascript 客户端中,我使用 jQuery 进行 ajax 调用:

<script>
        $.ajax (
            url: "http://localhost:8087/SpringMVC/users/user1",
            beforeSend: function (xhr)  xhr.setRequestHeader ("Authorization", "Basic xxxxxxxxxxxx"); ,
            success: function(val)  console.log(val); alert("success" + val); ,
            error: function(val)  console.log(val); alert("error" + val); 
        );
</script>

我的问题是 jQuery 没有在 HTTP 请求中发送 Authorization 标头,我不知道为什么。我不明白,因为我是在 beforeSend 方法中做的,所以它应该在 HTTP 请求中。结果:我遇到了 401 错误。

当我从同一个域 localhost:8087(不再是跨域)尝试脚本时,我没有问题。

这怎么可能?

我的脚本只是一个测试。我不打算将我的用户名/密码放在客户端。但我想测试如何对基本的身份验证保护的 REST API 进行 ajax 调用。我想我必须在服务器端发送以确保我的用户名/密码的安全,REST API 向我发回一个 cookie,我不需要再将用户名/密码传递给我对 REST API 的下一次 ajax 调用。我说的对吗?

我已经使用 Chrome Advanced REST 客户端测试了我的 REST API,它的工作原理就是这样。对于第一个请求,我需要传递授权标头。然后就不需要了。我的 javascript Web 客户端也应该这样工作吗?我打算使用 Node.JS 和 Backbone 来构建它。

非常感谢。

EDIT2 :似乎确实是 CORS 浏览器问题。我在服务器端为 OPTIONS 方法添加了标题 Access-Control-Allow-Methods,它适用于 Chrome。我可以毫无错误地访问 JSON 响应。但我仍然需要为下一个请求使用授权标头。如何告诉 jQuery 使用发送的 cookie?

当我尝试使用 Firefox 11 时,我无法访问 json 响应并且出现错误:

"NetworkError: 401 Non-Autorisé - http://localhost:8087/SpringMVC/users/user1"

【问题讨论】:

你是base64编码你的用户名/密码吗? 是的,我输入的是 xxxxxxxx 而不是真实的用户名:密码。 【参考方案1】:

显然,Chrome 和 Firefox 对跨域请求的处理方式有所不同。 在进行跨域请求之前,他们使用 HTTP OPTIONS 方法执行所谓的“预检”请求。 Chrome 和 Firefox 之间的区别在于 Chrome 还会发送带有凭据的 Authorization 标头,而 Firefox 则不会。

然后,它仍然是 Spring Security 配置问题。我的 url /users/* 对于所有 HTTP 方法都是安全的,包括 OPTIONS。对于 Firefox,由于未发送 Authorization 标头,因此我的请求未获得授权。如果我将我的安全 url /users/* 仅限于 GET 方法,那么它非常适用于 Firefox。所以我只需要在我的 Spring 安全配置中添加它:

<intercept-url pattern="/users/*" access="isAuthenticated()" method="GET"/>

之后,我可以选择:我可以在拦截 URL 中添加其他要保护的方法,除了 OPTIONS,或者我可以在 Spring MVC 控制器中将 HTTP 方法调用限制为 GET,这甚至会处理我的 OPTIONS 调用根据Javadoc。我选择了第二种解决方案。但是,如果有人找到一种解决方案来强制 Firefox 像 Chrome 一样发送凭据,那就太好了,我会选择这个。

【讨论】:

【参考方案2】: rico 提出的 Spring Security 配置方案的另一个选项是:
<http ... use-expressions="true">
    <intercept-url pattern="/users/*" access="permitAll" method="OPTIONS"/>
    <intercept-url pattern="/users/*" access="isAuthenticated()"/>
    ...
</http>

HTTP OPTIONS 请求将始终通过身份验证,而任何其他 HTTP 方法都不会。

注意 &lt;http&gt; 元素中的 use-expressions XML 属性设置为 true。然后 Spring Security 将期望 &lt;intercept-url&gt; 元素的 access 属性包含 Spring EL 表达式,例如 permitAllisAuthenticated()

【讨论】:

以上是关于JQuery跨域基本认证调用的主要内容,如果未能解决你的问题,请参考以下文章

跨域ajax请求基本认证

Web Api 跨域基础认证

跨域API认证

跨域 jsonp 的基本操作方法

JWT(JSON Web Token)的基本原理

JWT(JSON Web Token)的基本原理