уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Библиотека 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.
А вот и ссылка на программу:
[download id=»56″ format=»1″]

0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
4 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
chromi
chromi
25/08/2010 03: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/06/2011 23:40

Здравствуйте!
Вы не могли бы приложить архив с файлами полного работающего примера?
Той же простой авторизации.
А то никак не пойму как сделать рабочий вариант и повозиться с им вживую

дмитрий
02/07/2011 05: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 и ничего не происходит
неавторизован пишет
 
что я делаю не так и как сделать чтоб работало?

Олег Агафонов
13/02/2016 16:02

В библиотеки есть утечка памяти — не хватает деструктора на уничтожение FParameters:

destructor TOAuthRequest.Destroy;
begin
FreeAndNil(Self.FParameters);

inherited Destroy;
end;