Еще раз про авторизацию на сервере livejournal.com
Дата публикации: 11.11.2007
Дата последней правки: 09.02.2023
Содержание
Введение
Эта статья является продолжением статьи Основы работы с сервером livejournal, в которой мы рассмотрели несколько видов авторизаций, которые могут быть использованы для написания клиента наподобие Semagic или LJ.NET. В этой статье мы с вами рассмотрим еще один способ авторизации на сайте livejournal.com (ЖЖ).
Рассмотренные ранее виды авторизации позволяют сделать только те операции, которые описаны в документации. Таким образом мы не сможем, например, получить доступ к подзамочным записям друзей, посколько для доступа к чужим записям (пусть даже только для чтения) нет соответствующей функции сервера по протоколу Flat или XML-RPC (по крайней мере их нет в документации). Эта статья как раз и описывает способ прочитать такие записи.
Авторизация
Если попытаться получить доступ к подзамочным записям, используя cookies, которые были получены при авторизации одним из способов, описанных в предыдущей статье, то у нас ничего не получится. Эти Cookies не дают нам прав на просмотр сообщений только для друзей. Таким образом получается, что должен быть еще какой-то способ авторизации.
Эмуляция отправки данных с формы
Давайте рассмотрим страницу авторизации на сайте ЖЖ, расположенную по адресу http://www.livejournal.com/login.bml. Если вы уже авторизованы на этом сайте в своем браузере, то нажмите кнопку "Выход" в правом верхнем углу. Итак, на этой странице неавторизованные пользователя видят две формы для входа в систему - в правом верхнем углу и слева в центре. Как ни странно, эти две формы работают по-разному. В данной статье мы рассмотрим авторизацию с помощью эмуляции отправки данных с нижней формы.
Если проследить с помощью какого-нибудь прокси-сервера, который может показывать передаваемые данные (я предпочитаю Proxomitron), что происходит при отправке данных с помощью этой формы, то мы увидим, что на сервер передаются следующие параметры:
chal | Оклик (Challenge) сервера |
response | Сформированный с помощью пароля ответ |
user | Имя пользователя |
password | Пароль. Значение этого параметра остается пустым |
lj_form_auth | Идентификатор формы |
action:login | Значением этого параметра является просто надпись на кнопке для отправки данных с формы |
Для авторизации требуются только первые три параметра. Параметр chal можно получить двумя способами. Можно загрузить страницу http://www.livejournal.com/login.bml и из полученного кода HTML выделить значение скрытого поля chal формы. В исходнике страницы этот параметр прописан следующим образом:
Но лучше, конечно, воспользоваться функцией getchallenge сервера с помощью протокола Flat или XML-RPC. Эту функцию мы уже использовали в предыдущей статье. Значение параметра response вычисляется точно так же, как и в методе авторизации Challenge/Response, рассмотренном ранее, а именно по формуле:
MD5(chal + MD5(password))
Все эти данные надо отправлять по адресу http://www.livejournal.com/login.bml. Если все сформировано правильно, то в ответе сервера мы получим довольно много cookies. Из всех cookies для успешной загрузки подзамочных записей нам нужны будут только cookies с именами ljloggedin (таких cookies будет две штуки с одинаковыми значениями) и ljmastersession. Именно эти cookies и надо подцеплять к следующему запросу, который и будет читать записи только для друзей. Разумеется, если останутся и другие cookie, то ничего плохого не произойдет.
Надо заметить, что при получении cookies в классе HttpWebRequest из .NET Framework необходимо установить значение параметра AllowAutoRedirect в false, иначе произойдет редирект на другую страницу и мы не сохраним cookies. Зато потом при использовании полученных cookies это значение должно быть true, так как при дальнейшей загрузке страницы с этими cookies происходит серия редиректов. Если AllowAutoRedirect будет равно false, то все эти редиректы придется отслеживать вручную.
Реализация
Для демонстрации этого метода я дополнил проект LJServerTest из предыдущей статьи возможностью читать подзамочные записи. Скачать обновленные исходники можно здесь. При загрузке страницы с указанным адресом откроется новое окно, в котором будет показана загруженная страница с помощью контрола WebBrowser.
Чтение подзамочных записей осуществляет метод GetPrivatePage() класса LJServer, который принимает три параметра: адрес загружаемой страницы, логин (имя пользователя) и пароль:
{
CookieCollection cookies = GetBaseCookie (login, password);
string res = GetPage (url, cookies);
return res;
}
Здесь мы сначала получаем cookies, выдаваемые при авторизации с помощью метода GetBaseCookie, а потом загружаем страницу, используя эти cookies. Получение cookies выглядит следующим образом:
{
// Получаем оклик сервера (см. предыдущую статью)
string lj_login_chal = GetChallenge ();
// Рассчитаем ответ как в методе авторизации challenge / response
string auth_response = GetAuthResponse (password, lj_login_chal);
// Строка запроса для отправки через форму
string textRequest = string.Format ("chal={0}&response={1}&user={2}",
HttpUtility.UrlEncode (lj_login_chal),
HttpUtility.UrlEncode (auth_response),
HttpUtility.UrlEncode (login));
byte[] byteArray = Encoding.UTF8.GetBytes (textRequest);
// Получаем класс запроса
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create ("http://www.livejournal.com/login.bml");
// Заполняем параметры запроса
request.Method = "POST";
// Запрещаем автоматический редирект, чтобы сохранить cookies, полученные на первой странице после запроса
request.AllowAutoRedirect = false;
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = textRequest.Length;
request.UserAgent = "LJServerTest";
// Очищаем коллекцию от старых cookie и добавляем туда новые
request.CookieContainer = new CookieContainer ();
// Заполняем параметры Proxy (_proxy == null, если прокси не используется)
request.Proxy = _proxy;
// Отправляем данные запроса
Stream requestStream = request.GetRequestStream ();
requestStream.Write (byteArray, 0, textRequest.Length);
// Получаем класс ответа
HttpWebResponse response = (HttpWebResponse)request.GetResponse ();
// Читаем ответ
Stream responseStream = response.GetResponseStream ();
StreamReader readStream = new StreamReader (responseStream, Encoding.UTF8);
string currResponse = readStream.ReadToEnd ();
readStream.Close ();
response.Close ();
// Оставим только самые необходимые cookies
CookieCollection newCollection = new CookieCollection ();
for (int i = 0; i < response.Cookies.Count; i++)
{
if (response.Cookies[i].Name == "ljloggedin" ||
response.Cookies[i].Name == "ljmastersession")
{
newCollection.Add (response.Cookies[i]);
}
}
return newCollection;
}
Обратите внимание, на строки кода, где формируется запрос. Не смотря на то, что при методе POST передаваемые параметры разделяются с помощью разделителя строк, здесь мы используем символ '&': "chal={0}&response={1}&user={2}". Запрос при этом будет сформирован как положено, но, если заменить амперсанды символами переводом строки, то авторизация не пройдет. В конце функции мы оставляем только cookies с именами ljloggedin и ljmastersession. Это сделано больше для демонстрации, чтобы показать, что и без других cookies все работает. В принципе, это делать не обязательно.
А для загрузки страницы с использованием cookies используется довольно простая функция:
{
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create (url);
// Заполняем параметры запроса
// Здесь мы разрешаем автоматические редиректы
request.AllowAutoRedirect = true;
request.Credentials = CredentialCache.DefaultCredentials;
request.Method = "GET";
request.CookieContainer = new CookieContainer ();
if (cookies != null)
{
request.CookieContainer.Add (cookies);
}
// Заполняем параметры Proxy (_proxy == null, если прокси не используется)
request.Proxy = _proxy;
// Получаем класс ответа
HttpWebResponse response = (HttpWebResponse)request.GetResponse ();
// Читаем ответ
Stream responseStream = response.GetResponseStream ();
StreamReader readStream = new StreamReader (responseStream, Encoding.UTF8);
string currResponse = readStream.ReadToEnd ();
readStream.Close ();
response.Close ();
return currResponse;
}
Заключение
Ну вот мы и рассмотрели еще один способ авторизации на сайте livejournal.com. Интересно, сколько еще разных методов авторизации таит в себе ЖЖ? :)
Ссылки
- Основы работы с сервером livejournal.
- Программная отправка комментариев в livejournal - продолжение серии статей про работу с сервером ЖЖ.
- Реализация бота для отправки комментариев в Живой Журнал на языке Python
Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.