Библиотека OAuth для Delphi уже не раз рассматривалась в блоге, но до практического её применения дело как-то не доходило. Сегодня я решил исправить ситуацию и рассмотреть применение библиотеки OAuth на примере использования при работе с Twitter API. Причин выбора именно этого API две:
1. Twitter с начала лета планирут отказаться от использования Base-авторизации для доступа к API. Вместо этого разработчикам настольных приложений предлагается использовать либо OAuth с PIN-кодом, либо XAuth.
2. Не так давно я рассматривал в блоге свою программу для сжатия ссылок Link Compressor, которая использует API Twitter'а для публикации сообщений со ссылками. В программе используется Base-авторизация. Поэтому, чтобы после отказа команды Twitter'а от Base-авторизации Link Compressor продолжал нормально функционировать, необходимо применить в её работе OAuth.
Вначале рассмотрим как выглядит алгоритм доступа к API Twitter'а с использованием OAuth.
1. После того как Вы зарегистрируете свое приложение в Twitter Вам выдается два ключа: Consumer key и Consumer secret.
2. Далее Вы должны отправить запрос на адрес http://api.twitter.com/oauth/request_token для получения значений oauth_token, oauth_token_secret.
3. После этого Ваше приложение должно выполнить GET-запрос на http://twitter.com/oauth/authorize. В запросе должны присутствовать полученные в п.2. параметры. Загруженная страница показывается пользователю. Пользователь вводит свой логин и пароль к аккаунту Twitter'а и жмет "Allow" (разрешить доступ).
5. Пользователю будет показан PIN-код, который он должен вернуть в приложение (ввести в Edit или сохранить иным способом в программе).
6. PIN-код отправляется в параметре oauth_verifier на адрес http://twitter.com/oauth/access_token. В результате Twitter вернет нам снова oauth_token, oauth_token_secret. Именно эти значения и будут использоваться в дальнейшем для доступа к API.
Здесь следует отметить что полученные на последнем шаге параметры oauth_token, oauth_token_secret не имеют срока давности. То есть запросив один раз авторизацию в твитере Вы можете в дальнейшем сколь угодно долго использовать полученые значения для доступа к API - главное обеспечить их безопасное хранение в реестре, файле и т.д.
Теперь перейдем к реализации примера. Как следует из алгоритма, для работы нам понадобится каким-либо образом показать пользователю страницу для ввода логина и пароля и получения PIN-кода. Я для этого создал в проекте Link Compressor'а дополнительную форму:

На форме содержится Edit для ввода PIN-кода, WebBrowser для отображения страницы для авторизации и PIN-кода, CheckBox для того, чтобы можно было сохранить параметры авторизации и кнопка TButton клик по которой завершит процесс авторизации. Для хранения и использования данных API твитера будем использовать следуюий класс:
type TTwitter = class(TObject) private FAuthorized: boolean; FSource: string; FTwitterClient: string; FTwitterClientVersion: string; FTwitterClientURL: string; FUserName: string; FPassword: string; FConsumer: TOAuthConsumer; FToken: TOAuthToken; FRequest: TOAuthRequest; FHMAC: TOAuthSignatureMethod_HMAC_SHA1; FKey: string; FSecret: string; FOAuth_token: string; FOAuth_token_secret: string; FAuthHeader: string; procedure SetSource(const Value: string); procedure SetTwitterClient(const Value: string); procedure SetTwitterClientVersion(const Value: string); procedure SetTwitterCLientURL(const Value: string); procedure AddCustomHeader(Sender: TObject; const Method: String; Headers: TStrings); procedure CheckResponce(const Responce:string); public constructor Create; function POSTCommand(URL: string; Params: TStringList): string; function GETCommand(URL: string): string; function Update(const Text: string): string; property Source: string read FSource write SetSource; property TwitterClient: string read FTwitterClient write SetTwitterClient; property TwitterClientVersion: string read FTwitterClientVersion write SetTwitterClientVersion; property TwitterClientURL: string read FTwitterClientURL write SetTwitterCLientURL; property Consumer: TOAuthConsumer read FConsumer write FConsumer; property Token: TOAuthToken read FToken write FToken; property Request: TOAuthRequest read FRequest write FRequest; property HMAC: TOAuthSignatureMethod_HMAC_SHA1 read FHMAC write FHMAC; property Key: string read FKey write FKey; property Secret: string read FSecret write FSecret; property OAuth_token: string read FOAuth_token write FOAuth_token; property OAuth_token_secret : string read FOAuth_token_secret write FOAuth_token_secret; property Authorized: boolean read FAuthorized write FAuthorized; end;
Я не буду сейчас подробно останавливаться на работе этого класса (рассмотрю только один метод), т.к. теже методы GETCommand и POSTCommand Вы можете посмотреть в этом посте, а такие методы как SetTwitterClientVersion, SetSource и пр. просто присваивают значения полям класса.
Теперь надо определиться с тем, как будет вызываться форма. Т.к. я внедряю OAuth в уже разработанную программу, то я решил пойти уже проложенным путем и начинать процесс авторизации с окна настроект программы:
По клику на кнопке "Авторизоваться" происходит первая часть авторизации, включающая в себя пункты 1 и 2 алгоритма и вызов формы авторизации.
Вначале о том как получаются первые значения oauth_token, oauth_token_secret. Листинг процедуры:
procedure StartAuthorization(var LoginURL: string); var URL, Tok: string; endpos: integer; Response: TStringList; Stream: TStringStream; HTTP: THTTPCli; begin try //создаем необходимые объекты //Key = Consumer Key; Secret = Consumer Secret Twitter.Consumer := TOAuthConsumer.Create (Twitter.Key, Twitter.Secret); Twitter.HMAC := TOAuthSignatureMethod_HMAC_SHA1.Create; //URL куда будем отправлять данные URL := 'http://twitter.com/oauth/request_token'; //создаем все необходимые параметры запроса Twitter.Request := TOAuthRequest.Create(URL); Twitter.Request := Twitter.Request.FromConsumerAndToken (Twitter.Consumer, nil, URL); Twitter.Request.Sign_Request(Twitter.HMAC, Twitter.Consumer, nil); //добавляем полученные параметры к URL URL := URL + '?' + Twitter.Request.GetString; //отправляем данные (используется ICS) Stream := TStringStream.Create; HTTP := THTTPCli.Create(nil); HTTP.RcvdStream := Stream; HTTP.URL := URL; HTTP.Get; Response := TStringList.Create; Response.Text := Stream.DataString; //анализируем ответ Tok := Trim(Response.Text); endpos := AnsiPos('&oauth_token_secret=', Tok); Twitter.OAuth_token := ''; Twitter.OAuth_token_secret := ''; Twitter.OAuth_token := Copy(Tok, 13, endpos - 13); Tok := Copy(Tok, endpos, Length(Tok)); Twitter.OAuth_token_secret:= Copy(Tok, 21, Length(Tok)); Twitter.Token := TOAuthToken.Create(Twitter.OAuth_token, Twitter.OAuth_token_secret); //генерируем URL для авторизации пользователя URL := 'http://twitter.com/oauth/authorize'; LoginURL := URL + '?' + 'oauth_token=' + Twitter.OAuth_token + '&' + 'oauth_token_secret=' + Twitter.OAuth_token_secret + '&oauth_callback=' + TOAuthUtil.urlEncodeRFC3986(CallbackURL); finally FreeAndNil(Response); FreeAndNil(HTTP); FreeAndNil(Stream); end; end;
Соответственно после того как сгенерирован URL авторизации Вы можете прямо здесь же в процедуре вызвать форму с WebBrowser'ом, например так:
WB.Navigate(LoginURL); Form.ShowModal;
Первая часть завершена. Теперь пользователь вводит логин и пароль вот в такую форму:

после чего вводит полученый PIN-код в Edit и жмет кнопку. Приступаем к финальной стадии авторизации - получению параметров OAuth для использования при доступе к API. Процедура выглядит следующим образом:
function Authorization(const PinCode: string): string; var URL, Tok: string; endpos: integer; Response: TStringList; Stream: TStringStream; HTTP: THTTPCli; begin try URL := 'http://twitter.com/oauth/access_token'; Twitter.Consumer := nil; Twitter.Consumer := TOAuthConsumer.Create (Twitter.Key, Twitter.Secret, CallbackURL); Twitter.Request.HTTPURL := URL; Twitter.Request := Twitter.Request.FromConsumerAndToken (Twitter.Consumer, Twitter.Token, URL); Twitter.Request.Sign_Request(Twitter.HMAC, Twitter.Consumer, Twitter.Token); //добавляем PIN-код в запрос URL := URL + '?' + Twitter.Request.GetString + '&oauth_verifier=' + PinCode; Response := TStringList.Create; Stream := TStringStream.Create; HTTP := THTTPCli.Create(nil); HTTP.RcvdStream := Stream; HTTP.URL := URL; HTTP.Get; Response.Text := Stream.DataString; Tok := Trim(Response.Text); endpos := AnsiPos('&oauth_token_secret=', Tok); Twitter.OAuth_token := ''; Twitter.OAuth_token := Copy(Tok, 13, endpos - 13); Tok := Copy(Tok, endpos, Length(Tok)); endpos := AnsiPos('&user', Tok); Twitter.OAuth_token_secret := ''; Twitter.OAuth_token_secret := Copy(Tok, 21, endpos - 21); Result := Twitter.OAuth_token_secret; finally FreeAndNil(HTTP); FreeAndNil(Stream); FreeAndNil(Response); end; end;
Теперь процесс авторизации можно считать завершенным и можно приступать к работе с API. Отправим новое сообщение в Твитер. Для этого используется метод Update класса TTwitter:
function TTwitter.Update(const Text: string): string; var TextPost, URL: string; Data: TStringList; begin URL := 'http://api.twitter.com/1/statuses/update.xml'; Data := TStringList.Create; TextPost := Format('status=%s', [Text]); Data.Add(TextPost); Result := POSTCommand(URL, Data); Data.Free; end;
Как видите здесь уже нет логина и пароля пользователя. Вместо этого генерируется подпись OAuth и отправляется в заголовках вместе с запросом на сервер.
Осталось только сказать, что в примере использовалась версия библиотеки, работющая с ICS, которую Вы можете скачать здесь и предложить Вам скачать обновленную версию Link Compressor'а для того, чтобы Вы могли увидеть действие библиотеки "вживую". Кстати, если скачаете программу можете обратить внимание, что все Ваши твиты, отправленные с помощью программы будут подписываться как отправленные с помощью программы LinkCompressor.
А вот и ссылка на программу:
Link Compressor(912.32 KB)
Как Вы думаете, что происходит после того как молодая семья покупает наконец-то новую квартиру? Нет, не празднует целый месяц новоселье. Семья узнает на деле, что такое качественный ремонт и отделка квартир. Как минимум обновляют потолки, которые не блещут даже в новостройках эстетичностью и прямотой углов :).
А если Вы сами являетесь профессионалом по ремонту квартир и сейчас без работы, то можете здесь поискать для себя выгодные предложения и вакансии.
-----------------------------
| Делись! | Загружай! | Плюсуй! |
| | |









25 Авг 2010 в 3:43 дп
hello,
nice work. perhaps you can help me with the modified twitter.pas. especially the procedures addcustomheader and checkresponce. i do not find any hint how to do it. so it would be very nice if you can post it here.
thank you in advance.
30 Июн 2011 в 11:40 пп
Здравствуйте!
Вы не могли бы приложить архив с файлами полного работающего примера?
Той же простой авторизации.
А то никак не пойму как сделать рабочий вариант и повозиться с им вживую
02 Июл 2011 в 5:45 дп
Здравствуйте!
Повторил форму как у вас на скриншоте и добавил обработчик
procedure TForm1.Button1Click(Sender: TObject);
begin
label2.caption:=Authorization(edit1.text);
Memo2.Lines.Text:=’followers:’+twitter.GetUserFollowers(json);
Memo3.Lines.Text:=’friends:’+twitter.GetFriends(json);
end;
procedure TForm1.FormCreate(Sender: TObject);
var loginurl,url:string;
begin
Twitter := TTwitter.Create;
Twitter.Key := ‘xCMWOSqX06aEcbZEDeE6yQ’;
Twitter.Secret := ‘evVCYDouqf4bd9aIDlnpwgiTzyT6totm37Ggqey1pPI’;
CallbackURL:=’http://tigrazone.narod.ru’;
StartAuthorization(loginurl);
WebBrowser1.Navigate(LoginURL);
end;
при нажатии на кнопку войти выводиться должны список followes и friends
но ошибка forbidden и ничего не происходит
неавторизован пишет
что я делаю не так и как сделать чтоб работало?