Сегодня расскажу, как использовать idHTTP.Post для авторизации на сайте. Я возьму для примера сайт LiveJournal.com.
Немного теории для начинающих. Итак, вызов метода Post компонента idHTTP отличается от вызова Get-а только тем, что помимо URL-а необходимо передать параметры. Параметры можно передавать в виде StringList-а, или каких-нибудь Stream-ов, или чего-нибудь еще подходящего.)
Пример Post-процедуры (параметры передаются в виде StringList-а):
procedure TForm1.Button1Click(Sender: TObject);
var
LoginInfo: TStringList;
Response: TStringStream;
begin
try
LoginInfo := TStringList.Create;
Response := TStringStream.Create('');
LoginInfo.Add('username=MyName');
LoginInfo.Add('password=MyPass');
IdHTTP1.Post('http://mywebsite.xxx/login.php',LoginInfo,Response);
Showmessage(Response.DataString);
finally
begin
Response.Free;
LoginInfo.Free;
end;
end;
end;
Пример Post-функции (параметры передаются в виде IdMultiPartFormDataStream-а):
uses IdMultipartFormData;
{ .... }
procedure TForm1.Button1Click(Sender: TObject);
var
data: TIdMultiPartFormDataStream;
begin
data := TIdMultiPartFormDataStream.Create;
try
// добавляем нужные параметры
data.AddFormField('param1', 'value1');
data.AddFormField('param2', 'value2');
// для примера выводим в мемо все, что вернулось
Memo1.Lines.Text := IdHTTP1.Post('http://localhost/script.php', data);
finally
data.Free;
end;
end;
Сейчас попробуем применить полученные знания. Идем на LiveJournal.com, включаем сниффер, логинимся на сайте и смотрим, какие параметры надо передавать ('mode=login', 'user=логин', 'password=пароль'). Авторизация не произойдет, если на стороне клиента не будут сохранены кукисы. Для сохранения кукисов среди компонентов Indy существует TidCookieManager. IdCookieManager подключается к idHTTP через свойство CookieManager.
idHttp.CookieManager := IdCookieManager;
В этом случае при запросах в заголовок добавляются кукисы, автоматически сохраненные в IdCookieManager. IdCookieManager можно найти на закладке Indy Misc или создать динамически.

Поместим на форму 2 TEdit-а, TMemo и кнопку, на которую повесим следующий работающий код авторизации:
procedure TForm1.Button1Click(Sender: TObject);
var
Http : TidHttp;
CM : TidCookieManager;
Data : TStringList;
StrPage, UserID, UserName : String;
i : integer;
begin
try
Http := TIdHTTP.Create(Self);
Data := TStringList.Create;
CM := TidCookieManager.Create(Http);
Http.AllowCookies := true;
Http.CookieManager := CM;
Http.HandleRedirects := true;
Http.Request.Host:='livejournal.com';
Http.Request.UserAgent:='Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10';
Http.Request.Accept:='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
Http.Request.AcceptLanguage:='ru,en-us;q=0.7,en;q=0.3';
Http.Request.AcceptCharSet:='windows-1251,utf-8;q=0.7,*;q=0.7';
Http.Request.Referer:='http://www.livejournal.com/';
Data.Add('mode=login');
Data.Add('user=' + Edit1.Text);
Data.Add('password=' + Edit2.Text);
StrPage := Http.Post('http://www.livejournal.com/login.bml?ret=1', Data);
finally
Data.Free;
CM.Free;
Http.Free;
end;
if Pos('<input class="logoutlj_hidden" id="user" name="user" type="hidden" value="'+Edit1.Text,StrPage) <> 0 then
ShowMessage('Авторизация прошла успешно')
else
ShowMessage('Авторизация провалилась');
Memo1.Lines.Text := StrPage;
end;
Возвращенные заголовки (после ответа сервера) можно посмотреть так:
idHttp.Response.RawHeaders.GetText;
Сохраненные в CookieManager-е кукисы можно посмотреть так:
for i := 0 to Http.CookieManager.CookieCollection.Count - 1 do
StrPage := StrPage + CM.CookieCollection.Items[i].CookieText + #13#10;
Вот что записал туда LiveJourmal.com:

Да, ЖЖ, мы тоже love you a lot :)
___
В качестве отступления от темы статьи делюсь ссылкой на сайт о программировании на Delphi для начинающих и не только.
___
Чтобы быть в курсе обновлений блога, можно подписаться на RSS.
Сугубо положительная статья. Большое спасибо. Давно искал что-то похожее.
ОтветитьУдалитьОдин вопрос: вот с ЖЖ вы указали, какие параметры передавать. А как с другими сайтами? Я не очень понял, какого рода "сниффер" здесь требуется. Можете что-нибудь посоветовать?
я думаю автор имеет в виду HTTP Analizer
ОтветитьУдалитьа как быть , если нужно еще передавать id сессии. Не ...как передавать эту id я понял...А вот как получить ее(его...id в общем) не загружая страницыи не парся исходник html?
ОтветитьУдалитьПодскажите пожалуйста, а как можно отправить куки на сервер?
ОтветитьУдалитьСПАСИБО ОГРОМНОЕ!
ОтветитьУдалитьА не сталкивали ли Вы с такой вот проблемой:
ОтветитьУдалитьВ длинном цикле идет обращение к скрипту php через IdHTTP.Post
и когда цикл переваливает через значения 3900, то выскакивает ошибка:
"Socket Error # 10048 Address already in use"
Как это побороть?
Вот кодинг:
http := TIdHTTP.Create(nil);
начало цикла:
if http.Connected then http.Disconnect;
Memo1.Lines.Append(http.Post('http://localhost/integrator.php', formData));
formData.Free;
if http.Connected then http.Disconnect;
конец цикла.
http.Free;
Я ни с чем таким не сталкивалась. А что, если попробовать создавать idHTTP в начале и в конце внутри цикла? ) Говорю наугад, может, со "свеженьким" объектом каждый раз будет работать лучше? Если, конечно, это не идет вразрез с алгоритмом.)
ОтветитьУдалитьМаша, большое спасибо за статьи. Я по ним научился работать с интернетом. А статьи по созданию многопоточных интернет-приложений будут?
ОтветитьУдалитьисходник хороший вопросов нет но как быть с передаче руского текста в кодировке win-1251 да еще +xml + openssl с етим всюголову свернул весь нет перекопал
ОтветитьУдалитьСтатья хороша....но есть вопрос
ОтветитьУдалитьАвторизация на сайте вконтакте.ру проходит успешно, но при попытке загрузить любую другую страницу этого сайта, то перикидывает на стр. входа т.к. идет неправильная обработка кукис, как я понял...
немогли бы вы помочь с решением данной проблемы?
Все эту проблему решил...
ОтветитьУдалитьнаписал свой обработчик куков
Очень полезная статья. Вот правда не получилось просмотреть куки. Выдает ошибку. Но это не столь важно. Сейчас столкнулся с проблемой авторизации на сайте на движке ucoz. Как на нем можно авторизоваться при помощи idhttp? Интересующая нас строка с сниффере насколько понял эта:user=мыло&password=пароль&rem=1&a=2&ajax=1&rnd=863HTTP/1.1 200 OK
ОтветитьУдалитьНе знаю, пробовали ли вы авторизоваться на ЖЖ при помощи, приведённого куска кода, у меня лично не получилось.
ОтветитьУдалитьПоискал ответ в гугле и вот что я нашёл. http://jenyay.net/Programming/LJServer2#auth
Оказывается не всё так просто, и для ЖЖ надо указывать схему авторизации а также шифровать данные функцией MD5
Полиморфыч, если бы я не пробовала - я бы не написала. На момент написания все отлично работало.
ОтветитьУдалитьvar
ОтветитьУдалитьHttp : TidHttp;
CM : TidCookieManager;
Data : TStringList;
StrPage, UserID, UserName : String;
i : integer;
begin
try
Http := TIdHTTP.Create(Self);
Data := TStringList.Create;
CM := TIdCookieManager.Create(Http);
Http.AllowCookies := true;
Http.CookieManager := CM;
Http.HandleRedirects := true;
Http.Request.Host:='connect.ua';
Http.Request.Connection:='keep-alive';
Http.Request.UserAgent:='Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10';
Http.Request.Referer:='http://connect.ua/';
Http.Request.ContentLength:=70;
Http.Request.CacheControl:='max-age=0';
Http.Request.ContentType:='application/x-www-form-urlencoded';
Http.Request.Accept:='application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5';
Http.Request.AcceptEncoding:='gzip,deflate,sdch' ;
Http.Request.AcceptLanguage:='uk-UA,uk;q=0.8,ru;q=0.6,en-US;q=0.4,en;q=0.2';
Http.Request.AcceptCharSet:='windows-1251,utf-8;q=0.7,*;q=0.3';
Data.Add('submit=1');
Data.Add('data[email]=' + Edit1.Text);
Data.Add('data[password]=' + Edit2.Text);
StrPage := Http.Post('http://connect.ua/login', Data);
for i := 0 to Http.CookieManager.CookieCollection.Count - 1 do
StrPage :=CM.CookieCollection.Items[i].CookieText + #13#10;
finally
Data.Free;
CM.Free;
Http.Free;
end;
Memo1.Lines.Text := StrPage;
end;
Що здесь не так ? Плизз!
Маша, спасибо огромное. Написано кратко и по делу. Авторизация на ЖЖ работает без каких-либо переделок.
ОтветитьУдалитьУ меня следующая проблема.
ОтветитьУдалитьНа странице, которую передаю в Post, есть перенаправление на другую страницу. После перенаправления происходит отключение. С чем это может быть связано?
С ходу сказать сложно, надо смотреть код.
ОтветитьУдалитьДоброго времени суток.
ОтветитьУдалитьМаша, тема, которую вы затронули в этом обзоре очень актуальна и мало где можно найти действительно толковое объяснение как у вас.
Код, который вы написали, работает исправно и на сегодняшний день, не знаю на что там жаловались до меня. Правда возникло несколько вопросов:
1) Как определить какие именно данные отправляются при регистрации? Было сказано, что вы использовали сниффер, а какой именно если не секрет?
P.S. установил Iris Network Traffic Analyzer, но как-то слишком непонятно там что к чему.
2) При запуске программы, в StrPage сохраняется код возвращаемой странички - это и есть залогиненая страничка. НО! как её открыть, скажем, в помещенном на форме WebBrowser-е?
Влад, чтобы посмотреть хэдеры запросов я обычно использую плагин к FF, о котором писала здесь: http://parsing-and-i.blogspot.com/2009/04/http.html
ОтветитьУдалитьКод странички, возвращаемой после авторизации, я использую просто для того, чтобы проверить, прошла ли она успешно. Дальше его использовать не надо, тем более не надо загружать в TWebBrowser. Все операции, которые вам необходимы, совершайте через idHTTP с использованием нужных заголовков и кукисов.
Если вы хотите работать с TWebBrowser - то это уже совсем другая история :)
Спасибо, плагин отличный, очень удобно им пользоваться.
ОтветитьУдалитьПравда на другой сайт, сколько ни мучился, у меня ,пока что, так и не получается залогиниться :)
А сайт, на который я пытаюсь залогиниться есть ни что иное как браузерная игрушка http://heroeswm.ru . Да да, а кому охота целый день просиживать за компьютером кликая туда сюда ))
Хотел скачать для ознакомления ваши исходники к игре Minicity, но ссылка оказалась не рабочей (Вот обзор с ссылкой на исходники: http://parsing-and-i.blogspot.com/2008/12/blog-post.html).
Не совсем понимаю в чем заключается проблема моего “творения”, если вы подскажете в каком направлении надо двигаться, надеюсь, у меня получится залогиниться.
Для начала порядок подключения:
1) Заполнить input с логином
2) Заполнить input с паролем
3) Нажать кнопку “Войти”. Но эта “кнопка ” не есть Button, а является полем input type=image name=lbut src='i/index/left_buttons21.jpg' title='Войти в игру!'. И при POST запросе сюда передаются переменные lbut.x и lbut.y – это, как я понял есть координаты картинки. Как их вычислить при POST запросе через IdHttp я не понял, и не знаю имеют ли они вообще критическое значение, так как эти координаты меняются, если например в браузере открываю боковую панель.
Проблема следующая: после отправки POST запроса с заполненными переменными на страничку http://www.heroeswm.ru/login.php :
Data.Add('LOGIN_redirect=1');
Data.Add('login=' + Edit1.Text);
Data.Add('lreseted=1');
Data.Add('pass=' + Edit2.Text);
Data.Add('preseted=0');
Data.Add('lbut.x=74'); // Координаты изображения заполняю “наобум”
Data.Add('lbut.y=5');
приходит перенаправление на “домашнюю” страницу персонажа http://www.heroeswm.ru/home.php :
HTTP/1.1 302 Found
Server: nginx
Date: Sat, 03 Jul 2010 11:18:45 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: sid=deleted; expires=Fri, 03-Jul-2009 11:18:44 GMT
Set-Cookie: pl_id=deleted; expires=Fri, 03-Jul-2009 11:18:44 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Set-Cookie: PHPSESSID=bd9ed3c4cac4b91ac27e2cf61c3f6f30; path=/; HttpOnly
Set-Cookie: pl_id=460703
Set-Cookie: sid=cbc7601ea52e771cad748cbb2bd55b17
Location: home.php
так как это перенаправление приходит всегда, то сразу после POST запроса открываю перенаправленную страничку следующим образом: Http.Get(Http.Response.Location). Но вот незадача, при попытке получить эту страничку я получаю не залогиненую страничку, а исходную страницу сайта http://heroeswm.ru , как будто программа и не отправляла POST Запрос.
Вот исходник моего чудо творения, если необходим: http://file.qip.ru/file/133760312/21e99199/Heroes_Connector.html
Влад, сейчас у меня, к сожалению, нет времени регистрироваться на том сайте и тестировать ваш код. Что могу посоветовать? Проверьте куки. CookieManager в непоследних версиях инди может глючить, помочь может или обновление инди, или разбор кукисов "вручную".
ОтветитьУдалитьМаша, вы правы, проблема скорее всего в кукисах. Посмотрел содержимое CookieManager-а, там полный хаос, одни и те же записи по 2-3 раза встреечаются + не отправляются нужные при POST запросе.
ОтветитьУдалитьНе подскажите как вручную можно очистить содержимое CookieManager-а и как добавить к отправляемым заголовкам нужные куки?
Влад, в двух строках не ответить. Поищите в интернете, на программерских форумах эта тема поднималась множество раз. Или просто обновите Indy :)
ОтветитьУдалитьБольшое спасибо, Мария! Информация оказалась крайне полезна.
ОтветитьУдалитьНе сохраняет все куки, только половину
ОтветитьУдалитьHttp := TIdHTTP.Create(Self);
ОтветитьУдалитьв этой строке что означает:
Self
я пишу на c++
Анонимный, в скобках в Delphi передается родитель. В с++, вроде, ничего не надо указывать, там для создания объекта другой синтаксис, если я ничего не путаю.
ОтветитьУдалитьProject proj.exe raised exception class EIdIOHandlerPropInvalid with message "IOHandler value is not valid"
ОтветитьУдалитьЧто это?Маша, плиз хелп. Ж-)
Miki, я не экстрасенс :)))
ОтветитьУдалитьвместо снифера юзаю плагин firebug для лисы или хрома счас раблтаю, так сказать, над регалкой аков жж с ручным вводом капчи. С инди начал знакомство недавно, так что вопрос наверное будет тупой. все параметры что которые должны идти в пост запросе записываются в виде LoginInfo.Add(username="edit1.text");
ОтветитьУдалитьи если значение всехпеременных является стринговыми то почему они в двойных, а не одинарных кавычках.и эти данные должны размещатся в том же порядке что и в снифере или это не важно. ещо раз извините за тупые вопросы, но есть желание научится.
seoblog, в коде не .Add(username="edit1.text");
ОтветитьУдалитьа .Add('user=' + Edit1.Text);
То есть пара значений в одинарных кавычках, просто формируется она из строки и свойства Text компонента Edit1. Что касается порядка, то он значения не имеет :)
Здравствуйте Маша.
ОтветитьУдалитьЧитал ваш блог уже давно, да и учился можно сказать по нему, но потом на долгое время забросил программирование. Но тут решил написать парсер яндекса, очень интересно стало :)
Программа уже написа, всё готово, подключил куки, IOhandler - SSL,
далее пост-запрос отправляю уверен, что правильный, но авторизация не проходит.
Data := TStringList.Create;
CM := TidCookieManager.Create(idhttp1);
idHttp1.AllowCookies:=true;
idHttp1.CookieManager := CM;
idHttp1.HandleRedirects := true;
IdHTTP1.Request.Host:='passport.yandex.ru';
idHttp1.Request.UserAgent:='Opera/9.80 (Windows NT 6.1; U; MRA 5.9 (build 4848); ru) Presto/2.7.62 Version/11.00';
idHttp1.Request.Accept:='text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
idHttp1.Request.AcceptLanguage:='ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3';
idhttp1.Request.Referer:='https://passport.yandex.ru/passport?mode=auth';
idhttp1.Request.ContentType:='application/x-www-form-urlencoded';
idhttp1.Request.Connection:='keep-alive';
idhttp1.Request.ContentLength:=200;
idhttp1.Request.Date:=now;
idhttp1.Request.AcceptEncoding:='gzip,deflate';
//IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Method:=sslvSSLv23;
{------------------------DATA------------------}
temp:=getidkey;
memo1.Lines.Add(temp);
data.Add('from=passport');
data.Add('retpath=https://mail.yandex.ru/');
data.Add('idkey='+temp);
data.Add('login='+edit1.text);
data.Add('passwd='+edit2.text);
data.Add('timestamp='+IntToStr(DateTimeToUnix(date+time)));
data.Add('twoweeks=yes');
try
StrPage:= idHttp1.Post('https://passport.yandex.ru/passport?mode=auth',data);
s:=idHttp1.Get('https://mail.yandex.ru/');
except
ShowMessage('error Post');
end;
if Ansipos('logout',StrPage)>0 then
ShowMessage('OK')
else
ShowMessage('ERROR');
Прошу вас совета, где мне лучше рыть проблему? Или всё-таки яндекс полностью блокирует такие программы и нужно использовать яндекс АPI ?
К сожалению, времени протестировать код сейчас нет. А так на ум ничего не приходит, почему не срабатывает. Сама уже давным-давно с Яндексом не работала :)
УдалитьОчень помогло)
ОтветитьУдалить