У каждого из нас есть свой план. Кто-то хочет стать космонавтом, кто-то банкиром, а третий уже начальник какой-нибудь компании и у него есть МЕГАплан – стать лидером на рынке чего-либо. И чтобы достичь поставленной цели необходимо чёткое планирование деятельности, постановка и контроль выполнения задач, постоянный мониторинг деятельности подчиненных и т.д. На крайний случай, необходимо всегда иметь под рукой элементарный список задач, чтобы наглядно видеть свою работу и работу других. Именно для таких целей и предназначен замечательный, на мой взгляд, он-лайн сервис “Мегаплан”. И, что замечательно, у Мегаплана появился недавно свой API, а это значит – есть, что использовать в Delphi. Но, вначале, пара слов о самом сервисе, чтобы было представление о том, с чем мы будем иметь дело.
Введение
Мегаплан предоставляет своим пользователям сразу несколько продуктов, каждый из которых рассчитан на свой круг деятельности. К примеру, продукт Таск-менеджер – это простенький сервис для ведения списка повседневных задач, Проджект-менеджер — это система управления проектами и взаимоотношениями с клиентами и т.д.
При регистрации нового аккаунта Вам дается 30-ти дневный бесплатный период использования без каких-либо ограничений, после чего Вы либо отказываетесь от дальнейшего использования продукта, либо переходите на платное обслуживание. Надо сразу сказать, что стоимость не такая уж и высокая. Например, Таск-менеджер обходится всего в 90 рублей в месяц. Почему бы не заплатить, если им удобно пользоваться? В принципе, я уже пообщался по телефону с тех.поддержкой Мегаплана и могу сказать, что беседой остался в целом доволен, равно, как и их дальнейшими планами на развитие (создание приложений под iPhod, iPhone, дальнейшее развитие API и т.д.) и, думаю, что можно будет прикупить Таск-менеджера для себя и своих нынешних коллег по работе.
При регистрации в Мегаплане Вам выдается свой URL для доступа к продукту. Например, мой тестовый аккаунт находится по адресу:
http://webdelphi.megaplan.ru
Здесь же (в своем аккаунте) я могу добавлять/удалять новых сотрудников, не заставляя их регистрировать собственные аккаунты в Мегаплане, а равно как и платить за использование продукта – все достаточно прозрачно и удобно.
Теперь, что касается API. На данный момент API Мегаплана ещё достаточно мал и по способу доступа к данным очень напоминает REST-интерфейс Amazon.com. Напоминает, НО не 1 в 1. Есть некоторые различия о которых мы сегодня и поговорим.
Итак, сегодняшний день посвятим двум задачам:
- Авторизуемся в Мегаплане по средствам API
- Научимся формировать правильные подписи запросов для получения данных, т.е. на сегодня ограничимся только GET-запросами.
Для работы будем использовать Delphi + Synapse. Из Synapse нам понадобятся следующие модули:
- httpsend.pas – для отправки запросов
- synacode.pas – для шифрования данных
- synautil.pas – для дополнительных преобразований данных, например для перевода строк в HEX-форму, формирования дат запросов и т.д.
Авторизация в Мегаплане
Для авторизации в сервисе нам необходимо отправить GET или POST на адрес:
адрес_аккаунта/BumsCommonApiV01/User/authorize.api
с двумя параметрами:
Login – Ваш логин доступа к аккаунту
Password – MD5 пароля в HEX-форме.
В ответ сервер отдаст нам JSON-массив с двумя ключами:
AccessID – открытый ключ доступа к аккаунту
SecretKey – секретный ключ, который мы будем использовать для формирования подписей.
JSON мы разбирать сегодня не будем, а процедура авторизации может выглядеть следующим образом (для моего тестового аккаунта):
var Post: TStringStream; Pass: string; begin with THTTPSend.Create do begin Pass:=StrToHex(MD5('password')); POST:=TStringStream.Create('Login=MyLogin&Password='+Pass); Document.LoadFromStream(POST); MimeType:='application/x-www-form-urlencoded'; HTTPMethod('POST','https://webdelphi.megaplan.ru/BumsCommonApiV01/User/authorize.api'); Memo1.Lines.LoadFromStream(Document); end; end;
После чего, в Memo1 выведется JSON-объект содержащий необходимые нам ключи AccessId и SecretKey, которые мы должны будем каким-либо образом сохранить. Здесь мы использовали для формирования строки пароля две функции:
MD5() – сформировала нам MD5 пароля (строки “password”)
StrToHex() из модуля synautil.pas перевела MD5 в HEX-форму.
Ну а дальше элементарная отправка POST и вывод ответа в Memo.
Формирование подписи и отправка GET-запросов
Как видите, авторизация – дело пары минут. С формированием подписи все несколько сложнее. Для доступа к какой-либо информации аккаунта посредствам API нам необходимо включать в заголовки запрос три заголовка:
- “Date:” – дата запроса
- “Accept: application/json”
- “X-Authorization: AccessID:Signature” – заголовок аутентификации
Если отправляется POST, то дополнительно в заголовки включается заголовок “Content-MD5”. И здесь, основная сложность состоит в том, чтобы правильно сформировать строку Signature. Это строка формируется на основании некой BaseString – строки содержащий сведения о запросе. Схема составления BaseString следующая:
BaseString = HTTP-Verb+LF+ContentMD5+LF+Content-Type+LF+Date+LF+HOST+URI
Здесь HTTP-Verb – тип запроса. Может принимать значения GET, POST, PUT, DELETE
LF – символ перевода строки ($0A)
ContentMD5 – MD5 тела запроса
Content-Type – тип данных, например, для POST это будет строка “application/x-www-form-urlencoded”
Date – дата запроса в формате RFC-822, например, Fri, 15 Oct 1999 21:14:56 +0200
HOST – хост вашего аккаунта, например webdelphi.megaplan.ru
URI – адрес куда отправляется запрос, например, для получения списка задач это /BumsTaskApiV01/Task/list.api
Следует обратить особое внимание на следующий момент: даже, если в запросе отсутствует какой либо элемент для формирования BaseString, например тип контента или MD5 тела документа, то символ перевода строки все равно должен присутствовать в строке.
Например, я хочу отправить GET-запрос на получение списка задач в своем аккаунте. В этом случае BaseString будет выглядеть следующим образом:
BaseString = GET$0A$0A$0AWed, 24 Nov 2010 13:42:39 +0600$0Awebdelphi.megaplan.ru/BumsTaskApiV01/Task/list.api
Теперь о том как формируется подпись на основании BaseString. Алгоритм достаточно прост:
- Шифруем BaseString, используя алгоритм HMAC-SHA1 (с ключом SecretKey)
- Полученное значение переводим в HEX-форму
- Полученное значение шифруем, используя Base64.
Функция для формирования подписи для GET-запроса может выглядеть следующим образом:
const LF = #$0a; var BaseString: TStringStream; HMACsig,RFCDate: String; begin BaseString:=TStringStream.Create; BaseString.WriteString(Method+LF);//метод (передается в параметрах) BaseString.WriteString(LF);//ContentMD5 отсутствует BaseString.WriteString(LF);//Content-Type отсутствует RFCDate:=Rfc822DateTime(Date);//формируем дату в формате RFC-822 (Date:TDateTime - передается в параметрах) BaseString.WriteString(RFCDate+LF); BaseString.WriteString(URI);//HOST+URI (передается в параметрах) HMACsig:=HMAC_SHA1(BaseString.DataString,SecretKey);//зашифровали по HMAC-SHA1 Result:=EncodeBase64((StrToHex(HMACsig)));//перевели в HEX и шифроали по Base64 BaseString.Free; end;
И теперь остается только отправить наш первый GET и получить данные. Сделать это можно таким образом:
var AccessID, SecretKey,URL: UTF8string; HTTP: THTTPSend; Date:TDateTime; ContentMD5,RFCDate:string; begin AccessID:='1234567890'; SecretKey:='asdasdasdasdasd'; HTTP:=THTTPSend.Create; URL:='webdelphi.megaplan.ru/BumsTaskApiV01/Task/list.api'; Date:=Now;//запомнили дату ContentMD5:=''; RFCDate:=Rfc822DateTime(Date); {формируем заголовки} HTTP.Headers.Add('Date: '+RFCDate); HTTP.Headers.Add('X-Authorization: '+AccessID+':'+CalcSigature('GET',SecretKey,URL,ContentMD5,Params,Date)); HTTP.Headers.Add('Accept: application/json'); {отправили запрос} HTTP.HTTPMethod('GET','http://'+URL); {вывели ответ} Memo2.Lines.LoadFromStream(HTTP.Document); HTTP.Free; end;
Ответ на этот запрос у меня получился следующий:
Далее остается использовать любую библиотеку для работы с JSON в Delphi, например, SuperObject и парсить ответ сервера. Обратите особое внимание на работу с датой – дата в заголовке запроса обязательно должна совпадать вплоть до секунды с той датой, которая использовалась при формировании подписи.
На сегодня все. Можете регистрироваться в Мегаплане и тестить его API :)
Книжная полка
Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
|
||
Название: О чем не пишут в книгах по Delphi
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
|
Супер!!! Спасибо!
Добый день. Прошу помощи. Пожалуйста отпишитесь! Делаю всё как описанно в статье http://chuckbeasley.wordpress.com/2009/04/29/using-oauth-for-delphi/ , пытаюсь достучаться до API Твиттера, но всё время идёт ошибка 401. Код в котором идёт ошибка. Остальное(Авторизация) проходит без проблем. function TMainForm.GETCommand(URL: string): string; var pos: integer; begin try Consumer := nil; Consumer := TOAuthConsumer.Create(Key, Secret, MY_Url); ARequest := TOAuthRequest.Create(URL); ARequest := ARequest.FromConsumerAndToken(Consumer, nil, URL); ARequest.HTTPURL := URL; Token := TOAuthToken.Create(OAuth_token, OAuth_token_secret); ARequest := ARequest.FromConsumerAndToken(Consumer, Token, URL); ARequest.Sign_Request(HMAC, Consumer, Token); pos := AnsiPos(‘?’, URL); if pos = 0 then URL := URL + ‘?’ + ARequest.GetString else URL := URL + ‘&’ + ARequest.GetString; Memo1.Text := MainIdHTTP.Get(Url); finally… Подробнее »
Прошу прощения…
[code]
function TMainForm.GETCommand(URL: string): string;
var pos: integer; begin try Consumer := nil; Consumer := TOAuthConsumer.Create(Key, Secret, MY_Url); ARequest := TOAuthRequest.Create(URL); ARequest := ARequest.FromConsumerAndToken(Consumer, nil, URL); ARequest.HTTPURL := URL; Token := TOAuthToken.Create(OAuth_token, OAuth_token_secret); ARequest := ARequest.FromConsumerAndToken(Consumer, Token, URL); ARequest.Sign_Request(HMAC, Consumer, Token); pos := AnsiPos('?', URL); if pos = 0 then URL := URL + '?' + ARequest.GetString else URL := URL + '&' + ARequest.GetString; Memo1.Text := MainIdHTTP.Get(Url); finally end; end;[/code]
в одной из статей на chuckbeasley.wordpress.com английским по белому сказано, что при использовании Indy возникает ошибка при доступе к API. Ошибка была решена ТОЛЬКО для латиницы. Если отправляете/получаете юникодную строку — ошибка сохраняется. Как вариант — использовать для работы с HTTP другие библиотеки, например ICS. Я использую библиотеку в LinkCompressor’e — работают и GET и POST-запросы.
Да. Я уже думал об этом, но не уверен точно. Ведь когда я через браузер иду по мною образованному запросу получаю ошибку 401, а когда на другой получаю, что такого nonce нету… ну как-то так.
Уверен, что я пишу неверную signature, может где-о ошибка :(
Отлично. Сам пользуюсь Мегапланом.
Раньше можно было получить в бесплатное пользование Free версию навсегда, чем я и пользуюсь до сих пор.