Тяжеловатая была неделька. Семь дней в работы, постоянные напряги, всё что-то кому-то надо…жесть. Но все когда-то заканчивается (слава богу, неделя кончилась) и сегодня решил запостить в блог новую статейку. И решил сделать этот пост, опять же, адресным — ответ на комментарий.
Цель сегодняшней работы: авторизоваться на сайте по 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 кнопки — в нем мы отправляем запрос и проверяем прошла ли авторизация:
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;
Обратите внимание на часть кода:
[...] 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:
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, надеюсь я не слишком опоздал с помощью и приведенный выше код Вам помог ;)
У меня проблема с Post’ом. Вообщем я по очереди отправляю 2 Post’а:
1. httpsend.HTTPMethod(‘post’,’https://assa.intertelecom.ua/ru/login’ ) который возвращает httpsend.ResultCode=301 как признак успешной авторизации на сайте
2. httpsend.HTTPMethod(‘post’,’https://assa.intertelecom.ua/ru/config’ )который возвращает httpsend.ResultCode=200 а должен 301. 200 я получаю при ‘get’ — почему вылазит у меня 200 и на пост? Или нельзя отправлять 2 поста?
Блин 3 часа пробился — не мог понять в чем проблема, решил у гуру спросить. Только написал сюда и нашёл ошибку. Пишу, да бы другие время не тратили за зря. Вообщем в начале объявляем
httpsend.MimeType:=’application/x-www-form-urlencoded’;
И входе считывания данных этот параметр поменялся. В следствии чего, при отправке запроса (‘post’) у меня он обрабатывался как get. Просмотрел все переменные в итоге и выявил, что httpsend.MimeType поменял значение. Перед 2ым запросам опять поставил нужное — пост обработался успешно.
ВООБЩЕМ: перед каждым постом как минимум перепроверяйте значение переменной httpsend.MimeType и будет Вам счастье
Dimrix, всегда приятно, когда вопрошающий не ждет пока я в блог залезу и прочитаю вопрос, а старается решить проблему сам :) Спасибо за коммент, думаю, что его прочитают ещё не один раз другие пользователи Synapse =)
Здравствуйте. Может быть кто знает, почему при подключении модуля ssl_openssl после запуска приложения главное окно появляется спустя ~2 секунды?
Sergey, может потому, что при подключении ssl_openssl срабатывает код в initialization модуля и там происходит где-то подвисание?
[…] Synapse. Авторизация на сайте. Работа с HTTPS. […]
Хм, у меня при добавлении модуля ssl_openssl тоже подвисает программа. Так и должно быть? Как избавится от подвисания? Это ведь не дело…
С Уважением.
Почему не дело? Synapse использует синхронные методы работы отсюда и «подвисания». Хотите чтобы ничего не висло — закиньте работу HttpSend в поток и не будет ничего зависать.
Спасибо. Замечательная статья.
Только я использовал не FireFox для просмотра (чего-то оно не пошло у меня), а встроенную возможность Opera, которая вызывается по Ctrl+Shift+I. И там закладка Сеть, а в ней Журнал сети.
Ну, и ещё, как новичок, не сразу въехал, что нужно в каталог программы подложить 2 библиотеки от пакета OpenSSL — это libeay32.dll и ssleay32.dll. Потому что исключение в synapse не генерируется — не сразу понял, почему httpsend.HTTPMethod() возвращает False. И ещё у меня получилось, что вместо about_abonent с сайта возвращается текст desktop (может уже на сайте поменяли чего…). Но а так работает.
if pos('/AB/about_abonent.khtml',GetLocation(httpsend.Headers))>0 then
«
>
» should be «>
» =)Большое спасибо за акцентирование на куске кода:
httpsend.Document.Clear;
httpsend.Headers.Clear;
так бы и не обратил внимания. Делал авторизацию в Яндекс.Паспорт, там три редиректа подряд. Что только ни пробовал, при первом же переходе по новому location сервер выдавал код 400 «Bad request». Эти две строчки решили проблему.
Есть неувязочка. Дело в том, что если пароль будет содержать символы «%» и прочие web-штучки, то при использовании
httpsend.MimeType:=’application/x-www-form-urlencoded’;
эти символы будут либо пропадать, либо заменяться. Получается, что авторизация не пройдет.
Как решить эту проблему?
Уже нашел решение :) Нужно предварительно обработать нужную строку методом EncodeURLElement из модуля SynaCode.
У меня нет ответа при запуске приложения под 64бит: if httpsend.HTTPMethod(‘post’,’https://partner.r01.ru/?’ ) then возвращает False как победить?
Dimrix, у меня Windows 7 x64 — нет никаких проблем. Или вы имеете в веду то, что вы собираете приложение «64-bit Windows» и у вас проблема?
В чем может быть причина, что в Windows 8.1 не выполняется запрос httpsend.HTTPMethod(‘post’,’https://partner.r01.ru/?’ ); ResultCode равен 500, а в windows 7 работает.
Сергей, столкнулся с такой же проблемой что и вы. Оказалось что я не переносил на тестовые машины 2 dll — библиотеки необходимые для работы программы с open-ssl(libssl32.dll, libeay32.dll). На Windows 7 действительно такой проблемы не было.
Александр благодарю за ответ, так есть, просто у меня на компе работало без проблем, что эта библиотека уже имелась в системной папке, занесенная делфи или еще кем, также и у других пользователей у кого работало, у кого нет по этой же причине, windows 8.1 в данном случае не грешит)
Пытаюсь получить страницу на этом сайте https://pw.mail.ru/account.php
Нормально получаю и могу получить много раз
После регистрации тут https://authdl.mail.ru/sz.php?hint=Auth
я страницу https://pw.mail.ru/account.php получить уже не могу
ResultCode=500
HTTPSend.Sock.LastErrorDesc = error:140A90F1:lib(20):func(169):reason(241)
пока не перегружу программу
Компонент пересоздаю, куки чищу — ничего не помогает
Не подскажите в чем проблема?
http://got.by/2g5ai6
75%
30 80%
http://got.by/2g5ai6