为什么我必须发送两个连续的HTTP Get请求进行身份验证?

Jer*_*dge 3 delphi http indy basic-authentication indy10

这是我先前问题的后续问题.我已经了解到,在请求中使用HTTP用户名/密码参数时,Get预计会有2个不同的请求发送到服务器.第一次尝试不包括用户名/密码凭据,但如果身份验证失败,则会发送另一个包含这些凭据的相同请求.

TIdHTTP然而,在使用Indy 时,它只发送一个请求,但是失败了Unauthorized.需要第二个相同的连续请求才能实际获得响应.

我想知道,这是设计,还是Indy的缺陷?

Jan*_*gen 6

这是因为使用了HTTP协商身份验证方法:

"NTLM和Negotiate(RFC-4559)最常用于Microsoft IIS Web服务器.NTLM可以独占使用,但现代服务器通常使用Negotiate来选择将使用哪种方案.结果通常是NTLM'

微软在这里解释它(见图1)

如果您使用Google进行http请求协商www-authenticate,您将找到更多信息.

作为一个例子,这是我看到的SOAP,如果SOAPUI与Exchange Web服务建立经过身份验证的连接:

1>  >> "POST /ews/exchange.asmx HTTP/1.1[\r][\n]"
    >> "Accept-Encoding: gzip,deflate[\r][\n]"
    >> "SOAPAction: "http://schemas.microsoft.com/exchange/services/2006/messages/ResolveNames"[\r][\n]"
    >> "Content-Type: text/xml; charset=utf-8[\r][\n]"
    >> "Content-Length: 548[\r][\n]"
    >> "Host: webmail.ttbv.nl[\r][\n]"
    >> "Connection: Keep-Alive[\r][\n]"
    >> "User-Agent: Apache-HttpClient/4.1.1 (java 1.5)[\r][\n]"
    >> "[\r][\n]"
    >> "<soapenv:Envelope [\n]"
    [snip]
    >> "</soapenv:Envelope>[\n]"
    >> "[\n]"

1<  << "HTTP/1.1 401 Unauthorized[\r][\n]"
    << "Cache-Control: private[\r][\n]"
    << "Server: Microsoft-IIS/7.5[\r][\n]"
    << "X-AspNet-Version: 2.0.50727[\r][\n]"
    << "Set-Cookie: exchangecookie=a29f10ca2a6d484ea276737e87d8e733; expires=Wed, 13-Nov-2013 10:47:33 GMT; path=/; HttpOnly[\r][\n]"
    << "WWW-Authenticate: Negotiate[\r][\n]"
    << "WWW-Authenticate: NTLM[\r][\n]"
    << "X-Powered-By: ASP.NET[\r][\n]"
    << "Date: Tue, 13 Nov 2012 10:47:33 GMT[\r][\n]"
    << "Content-Length: 0[\r][\n]"
    << "[\r][\n]"

2>  >> "POST /ews/exchange.asmx HTTP/1.1[\r][\n]"
    >> "Accept-Encoding: gzip,deflate[\r][\n]"
    >> "SOAPAction: "http://schemas.microsoft.com/exchange/services/2006/messages/ResolveNames"[\r][\n]"
    >> "Content-Type: text/xml; charset=utf-8[\r][\n]"
    >> "Content-Length: 548[\r][\n]"
    >> "Host: webmail.ttbv.nl[\r][\n]"
    >> "Connection: Keep-Alive[\r][\n]"
    >> "User-Agent: Apache-HttpClient/4.1.1 (java 1.5)[\r][\n]"
    >> "Cookie: exchangecookie=a29f10ca2a6d484ea276737e87d8e733[\r][\n]"
    >> "Cookie2: $Version=1[\r][\n]"
    >> "Authorization: NTLM TlRMTVNTUAAB[snip]QgBWAA==[\r][\n]"
    >> "[\r][\n]"
    >> "<soapenv:Envelope [\n]"
    [snip]
    >> "</soapenv:Envelope>[\n]"
    >> "[\n]"

2<  << "HTTP/1.1 401 Unauthorized[\r][\n]"
    << "Server: Microsoft-IIS/7.5[\r][\n]"
    << "WWW-Authenticate: NTLM TlRMTVNTU[snip]AACAAAAFAAAAA==[\r][\n]"
    << "WWW-Authenticate: Negotiate[\r][\n]"
    << "X-Powered-By: ASP.NET[\r][\n]"
    << "Date: Tue, 13 Nov 2012 10:47:33 GMT[\r][\n]"
    << "Content-Length: 0[\r][\n]"
    << "[\r][\n]"

3>  >> "POST /ews/exchange.asmx HTTP/1.1[\r][\n]"
    >> "Accept-Encoding: gzip,deflate[\r][\n]"
    >> "SOAPAction: "http://schemas.microsoft.com/exchange/services/2006/messages/ResolveNames"[\r][\n]"
    >> "Content-Type: text/xml; charset=utf-8[\r][\n]"
    >> "Content-Length: 548[\r][\n]"
    >> "Host: webmail.ttbv.nl[\r][\n]"
    >> "Connection: Keep-Alive[\r][\n]"
    >> "User-Agent: Apache-HttpClient/4.1.1 (java 1.5)[\r][\n]"
    >> "Cookie: exchangecookie=a29f10ca2a6d484ea276737e87d8e733[\r][\n]"
    >> "Cookie2: $Version=1[\r][\n]"
    >> "Authorization: NTLM TlRMTVNT[snip]AVABUADcANAA=[\r][\n]"
    >> "[\r][\n]"
    >> "<soapenv:Envelope [\n]"
    [snip]
    >> "</soapenv:Envelope>[\n]"
    >> "[\n]"

3<  << "HTTP/1.1 200 OK[\r][\n]"
    << "Cache-Control: private[\r][\n]"
    << "Transfer-Encoding: chunked[\r][\n]"
    << "Content-Type: text/xml; charset=utf-8[\r][\n]"
    << "Server: Microsoft-IIS/7.5[\r][\n]"
    << "X-EwsPerformanceData: RpcC=2;RpcL=0;LdapC=1;LdapL=0;[\r][\n]"
    << "X-AspNet-Version: 2.0.50727[\r][\n]"
    << "Persistent-Auth: true[\r][\n]"
    << "X-Powered-By: ASP.NET[\r][\n]"
    << "Date: Tue, 13 Nov 2012 10:47:33 GMT[\r][\n]"
    << "[\r][\n]"
    << "877[\r][\n]"
    << "<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    [snip]
    << "</s:Envelope>"
    << "[\r][\n]"
    << "0[\r][\n]"
    << "[\r][\n]"
Run Code Online (Sandbox Code Playgroud)

在第一个收到的HTTP块中,服务器告诉我可以使用哪些协议.

所以第二个请求不是,因为你写的如果认证失败,那就是设计; 因此,第一次请求不得发送用户名和密码.