Несмотря на то, что движок WordPress имеет в своем составе XML-RPC, всё же иногда приходится прибегать к старым добрым методам авторизации через POST-запрос и парсить, парсить, парсить…Необходимость возникает, например, в случае, когда XML-RPC отключен в блоге.
Сегодня хотел было вернуться к Indy, но попробовав пару раз авторизоваться в своем блоге с использованием idHTTP, решил что геморное это дело — использовать Indy. И буквально за 10 минут накидал небольшой примерчик авторизации в WordPress-блоге с использованием Synapse.
Для работы нам понадобиться всего один модуль Synapse — httpsend.pas. Создадим новое приложение и подключим этот модуль в uses.
Теперь разместим на главной форме приложения следующие компоненты (см. рисунок):
в label5 будем выписывать результат авторизации («авторизовались» или «не авторизовались»), который будем определять самым простым способом — искать в загруженном документе подстроку «Log Out«, которая есть в админ.панели WordPress-блога:
Теперь, что касается технической стороны вопроса. Авторизация в блоге WordPress происходит следующим образом:
1. На странице блога http://blog.com/wp-login.php пользователь заполняет поля «Login» и «Password» и жмет кнопку «Log In»
2. Если логин и пароль правильные, то пользователя перенаправляют на страницу http://blog.com/wp-admin/
Форма запроса на ввод логина и пароля выглядит следующим образом:
<form name="loginform" id="loginform" action="http://webdelphi.ru/wp-login.php" method="post"> <p> <label>Username<br /> <input type="text" name="log" id="user_login" class="input" value="" size="20" tabindex="10" /></label> </p> <p> <label>Password<br /> <input type="password" name="pwd" id="user_pass" class="input" value="" size="20" tabindex="20" /></label> </p> <p class="forgetmenot"><label><input name="rememberme" type="checkbox" id="rememberme" value="forever" tabindex="90" /> Remember Me</label></p> <p class="submit"> <input type="submit" name="wp-submit" id="wp-submit" class="button-primary" value="Log In" tabindex="100" /> <input type="hidden" name="redirect_to" value="http://webdelphi.ru/wp-admin/" /> <input type="hidden" name="testcookie" value="1" /> </p> </form>
Соответственно параметры запроса у нас будут следующие:
log=логин
pwd=пароль
Можно было бы для полноты картины добавить параметры testcookie и redirect_to, но в целом они не играют для нас никакой роли, поэтому их можно не включать в запрос.
Теперь договоримся как буем осуществлять авторизацию с Synapse.
1. Отправляем POST-запрос
2. Проверяем заголовки на наличие «Location: »
3. Если заголовок с перенаправлением есть, то GET-запросом получаем содержимое страницы и проверяем результат авторизации. Сразу приведу листинг процедуры авторизации:
procedure TForm2.Button1Click(Sender: TObject); var d: TStringStream; s:string; begin with THTTPSend.Create do begin MimeType:='application/x-www-form-urlencoded'; d:=TStringStream.Create('log='+Edit1.Text+'&pwd='+Edit2.Text); Document.LoadFromStream(d); if HTTPMethod('POST',Edit3.Text+'/wp-login.php') then begin d.Clear; for S in Headers do begin if pos('location: ',LowerCase(s))>0 then begin if HTTPMethod('GET',copy(S,11,length(S)-10)) then begin Document.SaveToStream(d); break; end; end; end; if pos('Log Out',d.DataString)>0 then label5.Caption:='Авторизовались' else label5.Caption:='Не авторизовались' end; end; end;
Теперь разберемся, что происходит в процедуре.
MimeType:='application/x-www-form-urlencoded'; d:=TStringStream.Create('log='+Edit1.Text+'&pwd='+Edit2.Text); Document.LoadFromStream(d);
Обязательно указываем MimeType тип контента ‘application/x-www-form-urlencoded’. Кстати, то же самое необходимо и при работе с Indy, только там значение записывается в idHTTP.Request.ContentType.
Затем формируем строку запроса и записываем её в тело нашего POST-запроса.
if HTTPMethod('POST',Edit3.Text+'/wp-login.php') then begin [...] end;
Если POST-запрос успешно выполнен, то проверяем, что вернулось. В нашем случае мы должны проверить содержимое заголовков ответа сервера, что мы и делаем здесь:
for S in Headers do begin if pos('location: ',LowerCase(s))>0 then begin if HTTPMethod('GET',copy(S,11,length(S)-10)) then begin Document.SaveToStream(d); break; end; end; end;
Ищем в заголовках Headers заголовок «Location: » и, если таковой находится, то выполняем GET-запрос на адрес перенаправления. После чего, для удобства поиска, сохраняем тело ответного сообщения в поток d:TstringStream. Ну, а дальше элементарнейшая проверка:
if pos('Log Out',d.DataString)>0 then label5.Caption:='Авторизовались' else label5.Caption:='Не авторизовались'
Которая и дает нам ответ на вопрос о том как прошла наша попытка авторизации.
Как видите весь код авторизации занял чуть больше 25 строк кода. Может я уже отвык от использования Indy, но по-моему авторизация с использованием Synapse оказалась намного проще.
Кстати, следует обратить внимание на то, что для дальнейшей работы с WordPress-блогом необходимо всегда передавать серверу Cookies, которые объект THTTPSend всегда автоматически сохраняет (и вставляет в запрос) в своем свойстве Cookies:TstringList.
Indy
[code]var
post:TStringList;
result:string;
begin
post:=TStringList.Create;
try
// Параметры
post.Add('log=admin');
post.Add('pwd=123456');
post.Add('rememberme=forever');
post.Add('wp-submit=Войти');
post.Add('redirect_to=http://site.net/wp-admin/');
post.Add('testcookie=1');
// Отправляем данные
result:=IdHTTP1.Post('http://site.net/wp-login.php', post);
// Результат
if Pos('action=logout', result)>0 then
MessageDlg('Авторизация прошла успешно!', mtInformation, [mbOK],0)
else
MessageDlg('Авторизация Провалилась!', mtInformation, [mbOK],0);
except
post.Free;
end;[/code]
!!! Если пароль содержит символы ! » ? $ % ^ & ), то регистрация не проходит.
Не пробовали в этом случае подключать модуль httpapp и заворачивать пароль в функцию HTTPEncode? Должно помочь
Я в Делфи новичек. Спасибо, я попробую.
З.Ы. Блог отличный, много нужной информации. Буду заходить почаще :)
Спасибо. Заходите, всегда рад новым читателям :)
Код приведенный тут у меня не работает :(
а конкретнее? На каком шаге не работает? У меня все работает, авторизуется
ошибок не дает. просто не авторизует
Есть проблема с кириллицей… не могу передать русские символы методом post
как быть?
делаю так:
[code]
with HTTPSend do
begin
MimeType := 'application/x-www-form-urlencoded';
D := TStringStream.Create();
D.WriteString('cat_name=' + RName);
Document.LoadFromStream(D);
if HTTPMethod('POST', Edit1.Text + '/wp-admin/categories.php') then
begin
...
end;
end;
[/code]
тут если RName — содержит кириллицу вообще ничего не записывает. Если только латинские символы (имеется ввиду если в тексте нет русских букв) записывает нормально.
как решить вопрос?
что я упустил?
вопрос снят
Доброго времени суток. Это снова я :)
Есть задача такого характера:
Необходимо создать новую запись в блоге…но надо сразу задать линк латиницей.
как это сделать?
synapse delphi 2009
Может вопрос мой непонятен. Тогда попробую пояснить.
Я synapse не юзал ранее…поэтому прошу подойти к вопросу снисходительно :)
Вопрос:
Собираюсь добавить новую запись через ../wp-admin/post-new.php
но тут только после вводе текста названия записи (заголовка) js формирует в div — innerhtml (надеюсь так понятнее). При этом он создает в линк последнюю часть как полное соответствие заголовка записи, а заголовок ессно на русском.
Требуется формировать линк латиницей. Как быть в данной ситуации?
+ как в synapse можно изменять значения объектов страницы (аналог document.GetElementById() или document.GetElementByTageName()) ? .. и вообще это можно сделать средствами synapse ?
Заранее благодарю за ответы
Никак. Synapse как и Indy, как и ICS и прочие библиотеки — это средства для работы с протоколом, а не DOM страницы. Для работы с элементами страницы используйте MSHTML и пр. библиотеки.
Раз вам нужно создавать новый пост в блоге, то огда может не стоит изобретать велосипед, а использовать XML-RPC вашего WordPress-блога?
Спасибо! Вы подали мне идею для брутера вп блогов)))
Здравствуйте. У меня в итоге пустой stringstream, а сниффер показывает, что сервер ответил и авторизация прошла успешно