如何使用 Indy 响应摘要式访问认证

How to response to digest access authentication with Indy

我正在尝试将响应发送回请求摘要式访问身份验证

的服务器
  ....
  FResponseHeader.Text := FResponseText;// received header.
  FResponseHeader.ProcessHeaders;
   ....
  WriteLn(FResponseHeader.WWWAuthenticate); //WWW-Authenticate: Digest realm="xxxx.com", nonce="fq1uvocyzvr17e6a5syproazd5phwdvhvlc5", stale=false, algorithm=MD5, qop="auth"
  LIdAuthentication := TIdDigestAuthentication.Create;
  try
    LIdAuthentication.Username := FUser;
    LIdAuthentication.Password := FPass;
    LIdAuthentication.Uri      := FURI;
    LIdAuthentication.Method   := GetMsgTypeString(FResponseHeader.RequestMethods);
    LIdAuthentication.Params.Values['Authorization'] := FResponseHeader.WWWAuthenticate;
    LIdAuthentication.AuthParams.AddValue('Digest', FResponseHeader.WWWAuthenticate);
    for I := 0 to LIdAuthentication.Steps do
      LIdAuthentication.Next;
    Result := LIdAuthentication.Authentication;
  finally
    LIdAuthentication.Free;
  end;

我从服务器得到了 401

创建授权的正确方法是什么Header

TIdDigestAuthentication(以及其他 TIdAuthentication 派生的 类)旨在与 TIdHTTP 一起使用,而不是独立使用。

如果您使用 TIdHTTP 与服务器通信,则根本不需要手动管理摘要式身份验证。如果服务器在其 WWW-Authenticate header 中请求 Digest,并且如果 IdAuthenticationDigest(或 IdAllAuthentications)在您的 uses 子句中,则 TIdHTTP 将自动为您发送摘要响应。您唯一需要关心的事情是:

  • 为初始身份验证尝试设置 TIdHTTP.Request.UsernameTIdHTTP.Request.Password 属性。

  • 设置一个 TIdHTTP.OnAuthorization 事件处理程序来处理服务器拒绝当前 Username/Password 的可能性,以便您可以提供新的重试值,可选在提示用户之后。

  • 可选地设置一个TIdHTTP.OnSelectProxyAuthorization事件处理程序来选择在服务器请求多个方案时使用哪个认证方案,and/or如果你想控制哪个方案优先超过其他人。

例如:

uses
  ..., IdHTTP, IdAuthenticationDigest;

...

IdHTTP1.OnAuthorization := AuthRequested;
IdHTTP1.Request.Username := ...; // initial username
IdHTTP1.Request.Password := ...; // initial password
IdHTTP1.Get(...);

...

procedure TMyClass.AuthRequested(Sender: TObject; Authentication: TIdAuthentication; var Handled: Boolean);
begin
  if (new credentials are available) then
  begin
    Authentication.Username := ...; // new username
    Authentication.Password := ...; // new password
    Handled := True;
  end else
    Handled := False;
end;

也就是说,如果您想独立使用 TIdDigestAuthentication,那么您应该像 TIdHTTP 使用它一样使用它,例如:

LIdAuthentication := TIdDigestAuthentication.Create;
try
  LIdAuthentication.SetRequest(FGetMsgTypeString(FResponseHeader.RequestMethods), FURI);
  LIdAuthentication.Username := FUser;
  LIdAuthentication.Password := FPass;
  LIdAuthentication.Params.Values['Authorization'] := LIdAuthentication.Authentication;
  LIdAuthentication.AuthParams := FResponseHeader.WWWAuthenticate; // assuming WWWAuthenticate is a TIdHeaderList...

  repeat
    case LIdAuthentication.Next of
      wnAskTheProgram:
      begin
        // set LIdAuthentication.Username and LIdAuthentication.Password to new credentials to retry...
      end;

      wnDoRequest:
      begin
        // send new request with LIdAuthentication.Authentication in the 'Authorization' header...
        Result := LIdAuthentication.Authentication;
        Exit;
      end;

      wnFail:
      begin
        // error handling ...
        Result := '';
        Exit;
      end;
    end;
  until False;
finally
  LIdAuthentication.Free;
end;