#delphi #post #http-status-code-401 #idhttp
#delphi #Публикация #http-status-code-401 #idhttp
Вопрос:
Я пытаюсь отправить XML-файл с помощью TIdHTTP.Post()
метода. Я видел много примеров в вопросах здесь, на сайте, но я не нашел ни одного, который соответствовал бы тому, что я делаю.
Мне нужно сначала войти в веб-сервис, и он возвращает мне SessionID
и UserAuth
, а затем мне нужно отправить 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;
Во втором сообщении я получаю ответ:
HTTP / 1.1 401 Неавторизованный
Ниже приводится выдержка из документации:
URL-адрес, где можно увидеть описание сервисов, является следующим: https://svchomologacao.sigen.cidasc.sc.gov.br
которая указывает на тестовую базу данных CIDASC, так что компании, предоставляющие ИТ-услуги для пестицидов, далее именуемые EIS, могут интегрировать свои программы через ВЕБ-службы.
После того, как интеграция HIA будет одобрена CIDASC, URL, который будет использоваться для отправки официальных данных, будет следующим:http://sigensvc.cidasc.sc.gov.br
где рецепты будут храниться в производственной базе данных CIDASC.
authToken — это комбинация (кодирование) в BASE64 (www.base64encode.org ) и в UTF-8 логин и пароль специалиста, выдавшего рецепт, разделенные двоеточием (:), как показано ниже:
пример: профессиональный пользователь: professionalpass
Из приведенного выше примера сгенерированный authToken будет выглядеть следующим образом: dXN1YXJpb2RvcHJvZmlzc2lvbmFsOnNlbmhhZG9wcm9maXNzaW9uYWw =
Чтобы установить соединение с сервером cidasc, для передачи предписаний конкретной EIS следует вызвать метод входа в систему службы доступа, как показано ниже:
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.
After changing HTTPS it was like this:
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 Сброс соединения одноранговым узлом
Я связался со службой поддержки по электронной почте, и они сказали мне, что данные UserAuth и SessionID должны быть отправлены в файле cookie заголовка вызова include, и отправили пример на 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.
Комментарии:
1. Вы УВЕРЕНЫ, что должны отправлять
SessionID
иUserAuth
в их собственных HTTP-заголовках, а не в HTTPAuthentication
заголовке или в строке запроса URL? У вас есть документация для REST API этого сервера, которой вы можете поделиться? Я также нахожу подозрительным, что сервер разрешил небезопасныйAuthToken
, не требуя HTTPS для его защиты. Любой злоумышленник MITM может таким образом украсть ваши учетные данные имени пользователя / пароля.2. Предоставленная вами документация вообще не содержала никакой полезной информации относительно использования
SessionID
/UserAuth
во втором СООБЩЕНИИ. И вы не должны использоватьsslvSSLv2
. Это для SSL 2.0, который больше не является безопасным, и его больше никто не поддерживает. Вместо этого используйтеsslvTLSv1
или выше.
Ответ №1:
Основываясь на электронном письме, которое вы получили от службы поддержки сервера, вам необходимо создать HTTP cookies для значений SessionID
и UserAuth
, а не создавать отдельные HTTP заголовки, как вы пытались изначально. Две совершенно разные вещи.
Для этой задачи можно использовать TIdCookieMananger
компонент Indy, например:
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;