XML 在 header 中使用授权上传文件,错误 401

XML file upload with Authorization in header, error 401

我正在尝试通过 TIdHTTP.Post() 方法发送 XML 文件。我在网站上的问题中看到了很多示例,但我没有找到适合我正在做的事情的示例。

我需要先登录到网络服务,它 returns 我 SessionIDUserAuth,然后我需要使用这个发送 XML 文件信息。

这是我的做法:

var
  IdHTTP : TIdHTTP;
  params : TMemoryStream;
  vResponse : TStringStream;
  UserName, PassUser, URLogon, URSend, AuthUser: string;
  jsonObj, jSubObj: TJSONObject;
begin
  IdHTTP := TIdHTTP.Create;
  vResponse := TStringStream.Create('');
  params := TMemoryStream.Create;
  UserName := '123456';
  PassUser := '12345678';
  AuthUser := string(EncodeBase64(AnsiString(UserName+':'+PassUser)));
  URLogon := 'http://svchomologacao.sigen.cidasc.sc.gov.br/Acesso/Login?authToken=' + AuthUser;
  URSend := 'http://svchomologacao.sigen.cidasc.sc.gov.br/Receituario/Incluir';

  IdHTTP.Post(URLogon, params, vResponse);
  Memo1.Lines.Add(vResponse.DataString);

  //this is the return I get from WS, the SessionID and UserAuth in JSon:
  jsonObj := TJsonObject.ParseJSONValue(vResponse.DataString) as TJsonObject; //Json conversion

  params.LoadFromFile('D:\Exemple.xml');

  IdHTTP.Request.CustomHeaders.Clear;
  IdHTTP.Request.Clear;
  IdHTTP.ConnectTimeout := 30000;
  IdHTTP.Request.BasicAuthentication := True;
  IdHTTP.Request.ContentType := 'application/xml';
  IdHTTP.Request.ContentEncoding := 'raw';
  IdHTTP.Request.Accept := 'application/xml';
  IdHTTP.Response.CharSet := 'UTF-8';
  IdHTTP.Request.UserAgent := 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; GTB5; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; Maxthon; InfoPath.1; .NET CLR 3.5.30729; .NET CLR 3.0.30618)';
  IdHTTP.Request.CustomHeaders.AddValue(jsonObj.Get(0).JsonString.Value, jsonObj.Get(0).JsonValue.Value);
  IdHTTP.Request.CustomHeaders.AddValue(jsonObj.Get(1).JsonString.Value, jsonObj.Get(1).JsonValue.Value);

  IdHTTP.Post(URSend, params, vResponse);
  ShowMessage(vResponse.DataString);
end;

在第二个 POST 中,我得到响应:

HTTP / 1.1 401 Unauthorized


以下是文档的节选:

The URL where the description of the services can be seen is: https://svchomologacao.sigen.cidasc.sc.gov.br

which points to the CIDASC test database, so that companies providing IT services to pesticides, hereinafter referred to as EIS, may integration of its programs via WEB Services.

After the HIA integration is approved by CIDASC, the URL which will be used to send the official data will be: http://sigensvc.cidasc.sc.gov.br

where the prescriptions will be stored in the production database of CIDASC.

authToken is the combination (Encode) in BASE64 (www.base64encode.org) and in UTF-8, the login and password of the professional that issued the prescription separated by a colon (:) as below:

ex.: professionaluser: professionalpass

From the example above, the generated authToken would be: dXN1YXJpb2RvcHJvZmlzc2lvbmFsOnNlbmhhZG9wcm9maXNzaW9uYWw =

To establish the connection with the cidasc server, in order to transmission of the prescriptions of a particular EIS should call the Login method of the Access service, as shown below:

svchomologacao.sigen.cidosc.sc.gov.br/Acesso/Login?authToken=xyz

where xyz will be the token obtained in step 2.

We remember that this method is POST, so that it will only operate via a call made by the software being developed by the EIS. For testing, existing programs may be used to such as POSTMAN.

SEND THE RECIPIENTS TO CIDASC After establishing the connection to the server, the EIS should call the Include method of the Receipt service, to send the recipients, as shown below:

svchomologacao.sigen.cidasc.sc.gov.br/Receituario/Incluir

From this point on, the system developed by the EIS individually, that is, it transmits the first one and waits for the response code of the method.

更改HTTPS后是这样的:

var
  IdHTTP : TIdHTTP;
  sshSocketHandler: TIdSSLIOHandlerSocketOpenSSL;
  vResponse : TStringStream;
  params : TMemoryStream;
begin
  IdHTTP := TidHTTP.Create;
  sshSocketHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
  sshSocketHandler.SSLOptions.Method := sslvSSLv2;
  IdHTTP.IOHandler := sshSocketHandler;
  params := TMemoryStream.Create;
  vResponse := TStringStream.Create('');

  IdHTTP.Post('https://svchomologacao.sigen.cidasc.sc.gov.br/Acesso/Login?authToken=MzQ3MjA1Mzk2OjM4MjY1OTk5', params, vResponse);
  Memo1.Lines.Add(vResponse.DataString);

现在我得到错误:

10054 Connection Reset by Peer


我通过电子邮件联系了支持人员,他们告诉我 UserAuth和SessionId数据必须在include调用的headercookie中发送,C#发送示例:

public void InvokeService(string xml){


    HttpWebRequest requestReceituarioCancelar = (
        HttpWebRequest)WebRequest.CreateHttp(
        @"https://svchomologacao.sigen.cidasc.sc.gov.br/Receituario/Cancelar"
    );

    requestReceituarioCancelar.Headers.Clear();
    requestReceituarioCancelar.ContentType = "application/xml;charset=\"utf-8\"";
    requestReceituarioCancelar.Accept = "application/xml";
    requestReceituarioCancelar.Method = "POST";

    XmlDocument SOAPReqBody = new XmlDocument();

    //ServiceResult: contains the login return (SessionID and UserAuth)

    var ServiceResult = StreamReceituarioLogin(requestLogin);

    var uri = new Uri("https://svchomologacao.sigen.cidasc.sc.gov.br");

    //Converts login return to json
    var retorno = JsonConvert.DeserializeObject<StructCookie>(ServiceResult); 

    //In the CookieContainer add the Uri containing the URL, SessionID and UserAuth 

    requestReceituarioCancelar.CookieContainer = new CookieContainer();
    requestReceituarioCancelar.CookieContainer.Add(uri, new Cookie("SessionID", retorno.SessionID));
    requestReceituarioCancelar.CookieContainer.Add(uri, new Cookie("UserAuth", retorno.UserAuth)); 

    SOAPReqBody.LoadXml(m);

    //Now it sends the requestReceituarioCancelar and the SOAPReqBody containing the XML
    Stream stream = null;
    using (stream = requestReceituarioCancelar.GetRequestStream())
    {
        SOAPReqBody.Save(stream);
        stream.Close();
    }
    using (WebResponse Serviceres = requestReceituarioCancelar.GetResponse())
    {
        using (StreamReader rd = new StreamReader(Serviceres.GetResponseStream()))
        {
            var ServiceResult = rd.ReadToEnd();
            rd.Close();
        }
    }
}

但我无法在 Delphi 中做同样的事情。

根据您从服务器支持团队收到的电子邮件,您需要为 SessionIDUserAuth 值创建 HTTP cookie,而不是创建individual HTTP headers 就像你最初尝试的那样。两个完全不同的东西。

您可以使用 Indy 的 TIdCookieMananger 组件完成此任务,例如:

var
  IdHTTP : TIdHTTP;
  sshSocketHandler: TIdSSLIOHandlerSocketOpenSSL;
  params : TMemoryStream;
  Response : string;
  UserName, PassUser, URLogon, URSend, URCookie, AuthUser: string;
  jsonObj: TJSONObject;
  Uri: TIdUri;
begin
  IdHTTP := TIdHTTP.Create;
  try
    sshSocketHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
    sshSocketHandler.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
    IdHTTP.IOHandler := sshSocketHandler;

    IdHTTP.CookieManager := TIdCookieManager.Create(IdHTTP);
    IdHTTP.AllowCookies := True;

    UserName := '123456';
    PassUser := '12345678';
    AuthUser := string(EncodeBase64(AnsiString(UserName+':'+PassUser)));

    URLogon := 'https://svchomologacao.sigen.cidasc.sc.gov.br/Acesso/Login?authToken=' + AuthUser';
    URSend := 'https://svchomologacao.sigen.cidasc.sc.gov.br/Receituario/Incluir';
    URCookie := 'https://svchomologacao.sigen.cidasc.sc.gov.br';

    params := TMemoryStream.Create;
    try
      Response := IdHTTP.Post(URLogon, params);
      Memo1.Lines.Add(Response);

      //this is the return I get from WS, the SessionID and UserAuth in JSon:
      jsonObj := TJsonObject.ParseJSONValue(Response) as TJsonObject; //Json conversion
      try
        Uri := TIdUri.Create(URCookie);
        try
          IdHTTP.CookieManager.AddServerCookie('SessionID=' + jsonObj.Values['SessionID'].Value, Uri);
          IdHTTP.CookieManager.AddServerCookie('UserAuth=' + jsonObj.Values['UserAuth'].Value, Uri);
        finally
          Uri.Free;
        end;
      finally
        jsonObj.Free;
      end;

      params.LoadFromFile('D:\Exemple.xml');

      IdHTTP.Request.Clear;
      IdHTTP.ConnectTimeout := 30000;
      IdHTTP.Request.Accept := 'application/xml';
      IdHTTP.Request.ContentType := 'application/xml';
      IdHTTP.Request.CharSet := 'utf-8';
      IdHTTP.Request.UserAgent := 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; GTB5; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; Maxthon; InfoPath.1; .NET CLR 3.5.30729; .NET CLR 3.0.30618)';

      Response := IdHTTP.Post(URSend, params);
      ShowMessage(Response);
    finally
      params.Free;
    end;
  finally
    IdHTTP.Free;
  end;
end;