Javascript/Ajax NTLM 身份验证

Posted

技术标签:

【中文标题】Javascript/Ajax NTLM 身份验证【英文标题】:Javascript/Ajax NTLM Authentication 【发布时间】:2013-09-02 21:05:28 【问题描述】:

我正在开发一个 html5 移动应用程序,它与 WebServices 通信。 WebServices 使用 NTLM 身份验证协议。我很难通过 javascript 处理握手。 NTLM 发送 401 unauthorized 作为对我的 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
);

【问题讨论】:

【参考方案1】:

据我所见,没有人使用 AJAX 实现 Windows 集成/NTLM 身份验证,尽管它应该是可能的(我正在考虑为当前项目执行此操作以将表单身份验证与 WindowsTokenRoleProvider 结合起来)

基本工作流程应该这样分解(基于文章here 和here):

    使用 base64 编码的 type-1 NTLM 消息执行 GET 请求 “授权”标头 采用 base64 编码的 type-2 NTLM 消息 401 响应中的“WWW-Authenticate”标头。 对上一步收到的 noonce 执行 NTLM 操作(抱歉,我还没有代码示例) 在“授权”标头中使用 base64 编码的 type-3 NTLM 消息执行最终 GET。这应该返回 200。

NTLM auth over HTTP 更像是一种使用 HTTP 的 CHAP 实现,而不是授权的 HTTP 请求。

如果我真的有时间实施这个,我会通知你的。抱歉,我无法提供更多帮助。

【讨论】:

上述所有四个步骤都应该由浏览器自动完成。我在生产中有一个可行的实现。 @QACollective 以及如何在我的网站中获取它?当我直接点击服务时,我的浏览器会这样做并且它可以工作。但这并不能阻止我的示例网站中的 fetch 调用以获取 401ed【参考方案2】:

是的,NTLM 不是很有趣。但你可能想试试这个,https://github.com/tcr/node-ntlm/blob/master/README.md

【讨论】:

【参考方案3】:

问题是您无法通过 javascript 获取当前登录的域/用户(或者如果可以,我从未找到解决方案)。

如果您已经知道域、用户名和密码,则可以使用 https://github.com/erlandranvinge/ntlm.js/tree/master 之类的内容

但我认为,从长远来看,采用这种单点登录方法会令人沮丧。

我们最终在隐藏的 iframe 中进行 NTLM 身份验证并通过 javascript 访问 iframe。

【讨论】:

这很好,注意:据我所知,没有办法使用它来执行 CORS(或 JSONP)。【参考方案4】:

您不必响应 NTLM(集成 Windows 身份验证)质询,如果配置正确,您的浏览器应该会为您完成。还可能出现许多其他并发症。

第 1 步 - 浏览器

检查浏览器是否可以使用 NTLM Web 应用程序或直接点击您正在开发的软件来访问和发送您的凭据。

第 2 步 - JavaScript withCredentials 属性

收到的 401 Unauthorized 错误和描述的症状与我未能将“withCredentials”属性设置为“true”时完全相同。我不熟悉 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.');
  
;

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

我怀疑人们最终遇到这个问题的一个主要原因是他们正在他们的工作站上开发一个组件,而另一个组件托管在其他地方。这会导致Cross-Origin Resource Sharing (CORS) 问题。有两种解决方案:

    在您的浏览器中禁用 CORS - 当您的工作最终将部署在与您的代码正在访问的资源相同的源上时,这对开发很有用。 在您的服务器上启用 CORS - 在更广泛的互联网上有大量阅读资料,但这主要涉及发送启用 CORS 的标头。

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

发送与所服务页面的来源相匹配的“Access-Control-Allow-Origin”标头...这不能是“*” 发送值为“true”的“Access-Control-Allow-Credentials”

这是我的 global.asax 文件中的工作 .NET 代码示例。我认为很容易看到正在发生的事情并在需要时翻译成其他语言。

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!
    

【讨论】:

以上是关于Javascript/Ajax NTLM 身份验证的主要内容,如果未能解决你的问题,请参考以下文章

HTTP 请求未使用客户端身份验证方案“Ntlm”未经授权从服务器接收到的身份验证标头为“NTLM”

Python 中的 NTLM 身份验证

WCF - 如何为 NTLM 身份验证配置 netTcpBinding?

NTLM 和自动匿名身份验证 IIS

核心中的 NTLM 身份验证 HttpClient

Active Directory 和 NTLM 身份验证