JavaScript/Ajax NTLM认证

23

我正在开发一款HTML5移动应用程序,该应用程序与WebServices通信。WebServices使用NTLM身份验证协议。我在处理JavaScript握手时遇到了困难。NTLM作为响应发送401未授权给我的POST请求,但我没有找到任何方法来响应它。

JavaScript是否支持NTLM身份验证?我应该建立一个代理Web服务(例如基本身份验证)吗?

我的jQuery调用类似于...

$.ajax({
                    type: "POST",
                    url: URL,
                    contentType: "text/xml",
                    dataType: "xml",
                    data: soapRequest,
                    username: 'username',
                    password: 'password',
                    xhrFields: {
                        withCredentials: true
                    },
                    success: processSuccess,
                    error: processError
});
4个回答

12

如果配置正确,您的浏览器应该为您响应NTLM(集成Windows身份验证)挑战,您不必自己回应。此外可能会有其他一些复杂情况。

第一步-浏览器

首先确保浏览器可以通过访问NTLM Web应用程序或者直接访问您正在开发的软件来发送您的凭据。

第二步-JavaScript withCredentials属性

当我没有将“withCredentials”属性设置为“true”时,我收到了401未经授权错误并描述了相同的症状。我不熟悉jQuery,但请确保您设置该属性的尝试成功。

以下示例对我有效:

var xhttp = new XMLHttpRequest();
xhttp.open("GET", "https://localhost:44377/SomeService", true);
xhttp.withCredentials = true;
xhttp.send();
xhttp.onreadystatechange = function(){
  if (xhttp.readyState === XMLHttpRequest.DONE) {
    if (xhttp.status === 200)
      doSomething(xhttp.responseText);
    else
      console.log('There was a problem with the request.');
  }
};

第三步 - 服务器端启用CORS(可选)

我猜很多人会遇到这个问题是因为他们正在本地开发一个组件,但该组件需要访问另一个位置托管的组件。这就引起了跨域资源共享(CORS)的问题。解决方案有两种:

  1. 在你的浏览器中禁用CORS - 开发时很好用,最终当你的工作部署在同一起源作为你的代码正在访问的资源上时。
  2. 在你的服务器上启用CORS - 在更广泛的互联网上有大量的阅读材料,但基本上涉及发送启用CORS的头文件信息。

简而言之,要启用CORS带凭据,您必须:

  • 发送匹配已服务页面的起源的 'Access-Control-Allow-Origin' 头文件 ... 不能是“*”
  • 发送值为'true'的 'Access-Control-Allow-Credentials'

这是我的.NET代码示例,在我的global.asax文件中可以工作。如果需要,我认为很容易看出正在发生什么并将其翻译成其他语言。

void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        Response.AddHeader("Access-Control-Max-Age", "1728000");
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (Request.Headers["Origin"] != null)
            Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
        else
            Response.AddHeader("Access-Control-Allow-Origin" , "*"); // Last ditch attempt!
    }
}

5
据我所了解,没有人使用AJAX实现过Windows集成/NTLM身份验证,尽管这应该是可能的(我正在考虑在当前项目中实现它,以将表单身份验证与WindowsTokenRoleProvider结合起来)。
基本工作流程应该如下所示(基于此处此处的文章):
  1. 使用Authorization头中的base64编码的类型1 NTLM消息进行GET请求
  2. 从401响应中的WWW-Authenticate头中取出base64编码的类型2 NTLM消息。
  3. 对前一步骤中收到的随机数执行NTLM操作(抱歉,我还没有代码示例)
  4. 在Authorization头中使用base64编码的类型3 NTLM消息执行最后一个GET。这应该返回200。
HTTP上的NTLM身份验证更像是使用HTTP的CHAP实现,而不是授权的HTTP请求。

如果我真的开始实施这个,我会通知你更新。很抱歉我不能提供更多帮助。


1
你上面列出的所有四个步骤都应该由浏览器自动完成。我已经在生产环境中实现了这个工作。 - QA Collective
1
@QACollective 是什么?我该如何将其添加到我的网站中呢?当我直接访问服务时,浏览器可以正常工作。但这并不能解决在我的示例网站中发起的fetch调用因401而失败的问题。 - Hobbamok

4
问题在于无法通过JavaScript获取当前已登录的域/用户(如果可以的话,我从未找到解决方案)。
如果您已经知道域、用户名和密码,您可以使用类似https://github.com/erlandranvinge/ntlm.js/tree/master这样的东西。
然而,在长期运行中,我认为采用此方法进行单点登录将会很令人沮丧。
我们最终在隐藏的iframe中进行了NTLM身份验证,并通过JavaScript访问了iframe。

这个不错,注意:据我所知,使用它没有方法进行CORS(或JSONP)。 - Gram

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接