Тяжеловатая была неделька. Семь дней в работы, постоянные напряги, всё что-то кому-то надо…жесть. Но все когда-то заканчивается (слава богу, неделя кончилась) и сегодня решил запостить в блог новую статейку. И решил сделать этот пост, опять же, адресным – ответ на комментарий.
Цель сегодняшней работы: авторизоваться на сайте по https-протоколу с использованием библиотеки Synapse.
Суть проблемы: не проходит авторизация при использовании метода HTTPMethod(), не устанавливаются новые cookies и т.д.
Целевой сайт: https://partner.r01.ru
Чтобы пост был полезен и интересен не только одному человеку, то позволю себе рассмотреть всю работы подробно.
1. Изучаем процесс авторизации
Первое, что я сделал – зарегистрировался на “проблемном” сайте и изучил подробно все запросы и заголовки запросов при авторизации.
В качестве просмотрщика заголовков использовался плагин к FireFox “Live Headers”.
Заголовок сообщения при авторизации методом POST выглядит следующим образом:
Ответ сервера при успешной авторизации:
При неудачной авторизации редирект (302) не происходит, несмотря на то, что cookies всё равно устанавливаются.
Таким образом, для того, чтобы авторизоваться на сайте с использованием Synapse нам необходимо:
- Сформировать и отправить по протоколу https запрос
- Определить в заголовке ответного сообщения либо редирект и перейти на новый адрес (при успешной регистрации) либо получить код 200 и констатировать провал “операции”.
2. Век живи – век учись
Первое, с чего я начал работу с Synapse – это отправил на сервер get-запрос с целью получить необходимые cookies, предположив, что авторизация на сайте будет схожа по принципу со способом из этого поста. А кукисы-то и не пришли, несмотря на то, что вроде бы никаких видимых ошибок в работе Synapse замечено не было.
Порывшись немного по Интернету, нашел небольшое примечания к работе с https-протоколом в Synapse. Дело в том, что
для правильной работы с https помимо модуля httpsend, необходимо использовать также модуль ssl_openssl из той же библиотеки.
Вот так вот. Теперь попробуем пройти весь путь авторизации. Открываем Delphi и создаем новый проект. У меня на главной форме размещены следующие элементы:
- 2 edit’а для воода логина и пароля;
- button с ничего не говорящим названием “Login”
- 2 Memo – в первый будем выводить все полученные кукисы и заголовки, а во второй – содержимое полученного документа после успешной авторизации.
Внешний вид программы у меня получился такой:
Может видок и неказистый, но, для тестов вполне достаточно.
Вначале приведу уже рабочий код обработчик события onClick кнопки – в нем мы отправляем запрос и проверяем прошла ли авторизация:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | procedure TForm5.Button1Click(Sender: TObject); function GetLocation(const headers:TStringList):string; var i:integer; begin for I := 0 to headers.Count - 1 do if pos('Location: ',headers[i])>0 then begin Result:=copy(headers[i],10,length(headers[i])-9); break; end; end; var stream: TStringStream; httpsend: THTTPSend; begin Memo1.Clear; Memo2.Clear; stream:=TStringStream.Create(''); stream.WriteString('wizard_domain2=&auid=&htid=&;action=1&login='+Edit1.Text+'&passwd='+Edit2.Text); httpsend:=THTTPSend.Create; httpsend.MimeType:='application/x-www-form-urlencoded'; httpsend.Document.LoadFromStream(stream); if httpsend.HTTPMethod('post','https://partner.r01.ru/?' ) then begin Memo2.Lines.Add('Отправка запроса. Ответ сервера'); Memo2.Lines.Add('-----Cokies-----'); Memo2.Lines.add(httpsend.Cookies.Text); Memo2.Lines.Add('-----Headers-----'); Memo2.Lines.add(httpsend.Headers.Text); if httpsend.ResultCode=302 then begin if pos('/AB/about_abonent.khtml',GetLocation(httpsend.Headers))>0 then begin httpsend.Document.Clear; httpsend.Headers.Clear; httpsend.HTTPMethod('get','https://partner.r01.ru/AB/about_abonent.khtml'); httpsend.Document.SaveToStream(stream); Memo1.Lines.Add(KOI8R2ANSI(stream.DataString)); end else Memo1.Lines.Add('Авторизация не удалась') end else Memo1.Lines.Add('Авторизация не удалась') end; end; |
Обратите внимание на часть кода:
1 2 3 4 5 6 7 | [...] if pos('/AB/about_abonent.khtml',GetLocation(httpsend.Headers))>0 then begin httpsend.Document.Clear; httpsend.Headers.Clear; httpsend.HTTPMethod('get','https://partner.r01.ru/AB/about_abonent.khtml'); [...] |
Всё дело в том, что при успешной авторизации редирект приходит на адрес:
/AB/about_abonent.khtml?regbase2_id=da…
и сколько раз я не пробовал получить документ по этому адресу – ничего не получилось. Поэтому поступил так “топорно” и всё сработало.
В ответном сообщении был получен документ содержащий html-код для страницы личного кабинета.
Ещё один “нестандартный” момент при работе с этим сайтом заключается в том, что страница приходит9 в кодировке KOI8-R и, следовательно, без дополнительной обработки текста мы получим вместо русского текста “кракозябры”.
Для того, чтобы избежать неприятных моментов с русскими буквами я использовал вот такую нехитрую функции перекодирования текста из KOI8-R в ANSI:
1 2 3 4 5 6 7 8 9 10 11 12 | function KOI8R2ANSI(S: string): string; var Ansi_CODE, KOI8_CODE: string; i: integer; begin KOI8_CODE := 'бвчздецъйклмнопртуфхжигюыэящшьасБВЧЗДЕЦЪЙКЛМНОПРТУФХЖИГЮЫЭЯЩШЬАС—Ј'; ANSI_CODE := 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ё'; Result := S; for i := 1 to Length(Result) do if Pos(Result[i], KOI8_CODE) > 0 then Result[i] := ANSI_CODE[Pos(Result[i], KOI8_CODE)]; end; |
Вот, пожалуй, и все, что касается авторизации на сайте https://partner.r01.ru.
P.S. Уважаемая,dkdk, надеюсь я не слишком опоздал с помощью и приведенный выше код Вам помог
Кстати, информация для будущих программистов. Закажите дипломный проект по программированию уже сейчас, а то потом не успеете.
Торопитесь получить сертификат на свои услуги? Срочная сертификация услуг www.rostest.net Вам обязательно поможет.
Прежде, чем покупать - линолеум цены в он-лайн и не тратьте лишнее время на разъезды по магазинам.
Если не знаете как правильно диван, то лучшее решение - это сборка мебели на дому от профессионалов
--------------------------------
Похожие записи:

24 Jan 2010 в 11:53 pm
Спасибо огромное)) помогло. Кстати, не поняла, почему у меня не срабатывало – ssl_openssl был подключен..
Теперь встал новый вопрос – скачивание файла))
https://partner.r01.ru/AB/auction2csv.khtml?ext=csv
должно происходить автоматическое скачивание файла. Пробую получать гетом этот адрес и делать http.document.savetofile..
причем и в случае, если сперва ходить на выдаваемый адрес (при этом 206 получаю, пытаюсь уже r01 снова идти, а дальше ничего). При этом откуда берется новая кука? Set-Cookie не было, а кука есть..
Заранее спасибо еще раз))
26 Jan 2010 в 10:58 am
HTTPGetFile не пробовали? Сообщения об ошибках были?
26 Jan 2010 в 9:58 pm
HTTPGetFile – вообще не нашла (( GetBinary – ничего вообще не выдает..
про куки и 206 – это я тормоз, забыла кэш вычистить))
по идее httpsend.HTTPMethod(‘get’,'https://partner.r01.ru/AB/auction2csv.khtml’); должно в ответ 200 давать, а вообще ничего не дает. Пусто. Не понимаю( Т.е. дело даже не в savetofile, а в самом гете..
27 Jan 2010 в 6:28 pm
Здравствуйте! Приведенная здесь информация оказалась очень полезной!
У меня возникла необходимо залогиниться на сайте ecod.ru работающему по протоколу https. Что вроде получилось не без вашего полезного примера)! Правда у данного сайта свои премудрости (при анализе заголовков при регистрации непосредственно из браузера не в одном из ответов сервера нет поля Location . Но перенаправление происходит, после трех Post запросов и двух Get. Все ответы сервера 200 ок!) Вроде я зарегился, но подозреваю о некорректности. Существует какой либо способ проверить цветут яблони на марсе или нет) по мимо заголовков сервера? Явных ошибок не выдает!
Пытаюсь скачать файл. После регистрации делаю Get запрос содержащий ссылку на необходимый файл в результате! Ответ 200 ок! содержащий строчку Content-Disposition: attachment; filename=”Order_Lenta_4502941838.xml” – это имя нужного мне файла! Причем ответ абсолютно одинаковый с заголовком ответа в браузере, разница лишь в том что в последнем выходит окно на сохранение данного файла! Пытки использовать функции
HttpGetBinary, HttpGetText –не к чему не привели! Уж очень нужен этот файл!Будете добры помочь новичку, Заранее благодарен!!!27 Jan 2010 в 6:44 pm
Mihail, а у Вас в гет запросе в явном виде файл указан? У меня просто сервер (r01.ru) вообще никакого ответа не выдает..
Я вот думаю, может у меня что-то с таймаутом, т.к. он и в браузере долго думает перед началом скачивания..
thx in advance)
27 Jan 2010 в 7:19 pm
<!– /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:”"; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:”Times New Roman”; mso-fareast-font-family:”Times New Roman”;} code {font-family:”Courier New”; mso-ascii-font-family:”Courier New”; mso-fareast-font-family:”Times New Roman”; mso-hansi-font-family:”Courier New”; mso-bidi-font-family:”Courier New”;} @page Section1 {size:612.0pt 792.0pt; margin:2.0cm 42.5pt 2.0cm 3.0cm; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} –>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:”Обычная таблица”;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:”";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:”Times New Roman”;
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
Нет запрос содержит ссылку!Делаю вот таким макаромhttpsend.HTTPMethod('get','https://ссылка');Если по логике, ответ сервера идентичный как и через браузер, можетsynapseпомещает его в системный буфер, тогда как его достать! Я совсем недавно работаю сsynapse!И еще вопрос не подскажите как программно перемещаться по сайту, так как ссылка на файл находиться в самой глубине сайта! Спасибо)27 Jan 2010 в 7:51 pm
подозреваю, что искать ссылку с синапс также, как и без него – делать поиск в получаемом документе по характерным особенностям ссылки. Т.е. после get
httpsend.document и в нем искать функцией pos необходимую ссылку)
А с закачкой файла у самой проблемы..)
27 Jan 2010 в 10:39 pm
Опчки…пока я тут в поте лица тружусь на ниве Российского образования в блоге уже прямо целая дискуссия назрела по поводу Synapse
Отлично. Ребята, dkdk, Mihail прошу Вас, если не получается решить проблему самостоятельно – подождите немного…совсем чуть-чуть. Я решу пару проблем на работе и займусь вашими вопросами, тем более самому жуть как интересно узнать почему не получается качнуть файлик.
сходу, сильно не задумываясь и не заглядывая на сайт, могу предложить вариант – немного проанализировать исходники загружаемых страниц и на основе какого-либо уникального куска кода страницы делать вывод об успешности “операции”. Ведь как ни крути не может быть так, чтобы нельзя было “вслепую” определить результат. Может мета-теги на страницах особенные есть или комментарии (хотя на них полагаться сильно не стоит, т.к. комменты имеют свойство исчезать).
Mihail, по поводу цветущих яблонь
Со скачиванием файлов надо посмотреть Synapse, вполне возможно, что ччего-то мы с Вами ещё не знаем. Будем разбираться совместно
28 Jan 2010 в 3:19 pm
<!– /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:”"; margin:0cm; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:12.0pt; font-family:”Times New Roman”; mso-fareast-font-family:”Times New Roman”;} code {font-family:”Courier New”; mso-ascii-font-family:”Courier New”; mso-fareast-font-family:”Times New Roman”; mso-hansi-font-family:”Courier New”; mso-bidi-font-family:”Courier New”;} @page Section1 {size:612.0pt 792.0pt; margin:2.0cm 42.5pt 2.0cm 3.0cm; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} –>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:”Обычная таблица”;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:”";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:”Times New Roman”;
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
Разобрался!) Делюсь опытом.Итак, изначально нам нужно найти ссылочку на наш файл! Для этого делаемGetЗапрос на страничку содержащею ссылочку на файл!httpsend.HTTPMethod('get','https://ссылка');Далее выгружаем результат запроса на жесткий дискhttpsend.document.SaveToFile('Директория\Страничка.xml');Анализируем полученную страничку, находим нужную ссылочку!ДелаемGetЗапрос на найденную ссылку файла!Записываем: httpsend.document.SaveToFile('Директория\файл’);И вот он, вот он наш файл!Наслаждаемся триумфом !!!)))28 Jan 2010 в 9:24 pm
Mihail, спасибо, что не забыли блог старины Vlad’а и поделились полезной информацией
Надеюсь, что и далее будете делиться с нами интересными моментами в работе с Synapse
29 Jan 2010 в 11:57 am
Vlad, Вам спасибо, за полезную статью, она дала правильное направление!)
01 Feb 2010 в 12:09 pm
Уважаемый Vlad. Спасибо за статью! Очень помогла смог авторизоваться на HTTPS сайте используюя библиотеку Synapse. Теперь стоит задача закачать туда на HTTPS файл. Пока только имею снятый при помощи Live Http headers образец как это делает обычный браузер. Не могу найти пример какие команды надо давать. Подскажите пожалуйста в каком направлении двигаться?
01 Feb 2010 в 8:18 pm
HTTPPostBinary или HTTPPostFile не использовали ещё? Попробуйте, должно сработать
02 Feb 2010 в 12:31 am
Здравствуйте, Vlad и все посетители данного блога. Есть у меня задумка написать программу для работы с Яндекс-Деньгами. Пробую залогиниться по аналогии с вашим примером – не получается..:
…
stream := TStringStream.Create(”);
stream.WriteString(‘retpath=http%3A%2F%2Fmoney.yandex.ru%2Fhistory.xml%3Fsys-req-id%3D51695425%26sha%3D1859bc1caec64a6f32418d05bdff6e9ea2701775&idkey=12t1265052585bMDTzoyBu×tamp=1265051458854&login=<логин>&passwd=<пароль>&In=%D0%92%D0%BE%D0%B9%D1%82%D0%B8′);
httpsend := THTTPSend.Create();
httpsend.MimeType := ‘application/x-www-form-urlencoded’;
httpsend.Document.LoadFromStream(stream);
if httpsend.HTTPMethod(‘post’, ‘https://passport.yandex.ru/passport?mode=auth&from=money&retpath=http%3A%2F%2Fmoney.yandex.ru%2Fhistory.xml%3Fsys-req-id%3D51695425%26sha%3D1859bc1caec64a6f32418d05bdff6e9ea2701775′) then
begin
…
end;
…
а в ответ получаю:
HTTP/1.1 302 Found
Server: nginx
Date: Mon, 01 Feb 2010 20:34:31 GMT
Content-Type: text/plain; charset=utf-8
Connection: close
Set-Cookie: yandex_mail=rushant; path=/; domain=.yandex.ru
Set-Cookie: yandex_login=rushant; path=/; domain=.yandex.ru
Set-Cookie: Session_id=1265056471.-5012146.0.16727186.2:123438673:350.8:1265056471740:1598965860:14.64210.7255.5f98480ecd70511da2d7940a9b74c3f2; path=/; domain=.yandex.ru
Set-Cookie: L=elUAUmB3b0J4fEcKWl9uc3V2YV8HX3cHEE4bVCg2HlETDwwnLyYtRQooWHNDLAcYLRg/RSwJVzciWQYLTFtUcg==.1265056471.6657.230156.a25cf4c710f62878daceb99c5691e68b; path=/; domain=.yandex.ru; expires=Sunday, 02-May-10 20:34:31 GMT
P3P: policyref=”/w3c/p3p.xml”, CP=”NON DSP ADM DEV PSD IVDo OUR IND STP PHY PRE NAV UNI”
Location: https://passport-ckicheck.yandex.ru/passport?mode=ckicheck&idkey=0Ee1265057671ToEe64_x7&ncrnd=816769
- Подскажите, что я делаю не так?
02 Feb 2010 в 12:47 am
Трудно ответить на вопрос, что не так, т.к. с Яндекс.Деньгами дела не имел в плане авторизации. А что должно быть? В смысле как выглядит заголовок сообщения об успешной авторизации? И ещё timestamp=1265051458854 – этот параметр влияет на авторизацию? Если его убрать, что получится?
02 Feb 2010 в 2:41 pm
Спасибо Vlad за совет. Пытаюсь сделать закачку через функцию HttpPostFile. Правда не до конца понятны те переменные которые необходимо указать для этой функции. function HttpPostFile(const URL, FieldName, FileName: string;
const Data: TStream; const ResultData: TStrings): Boolean;
С( const URL, FieldName, FileName: string;) вроде все понятно а вот остальное (const Data: TStream; const ResultData: TStrings) не совсем понимаю с чем едят и что я должен указать для них
09 Mar 2010 в 1:15 pm
Немного не в тему, поэтому прошу прощения заранее.
Недавно стояла задача NTLM авторизации. Побороть эту проблему на Delphi я не смог. Использовал сначала indy (с IdAuthenticationNTLM), потому по совету добрых людей попробовал synapse. Авторизация не поддалась
Опыта работы с http у меня практически нет. Не подскажите как реализауется в Delphi NTLM авторизация ? Может есть статьи на эту тему ? Примеры исходников ?
З.Ы. Проблему свою решил на C#. Но Delphi мне как-то ближе. Хотелось бы разобраться в проблеме до конца…
09 Mar 2010 в 1:18 pm
С этим я Вам врядли помогу, т.к. никогда не встречался с вашей проблемой. Может кто из читателей подскажет