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

Давненько я ничего не писал про Google API в Delphi, а между тем, разработчики из Google выпустили экспериментальный API, позволяющий нам без особых хлопот получить токен для авторизации в сервисах с помощью OAuth. Ранее OAuth использовался только для web-приложений.

Авторизация в сервисах Google теперь стала напоминать, что-то наподобие OAuth-авторизации в Twitter, т.е. вначале получаем код доступа, затем меняем его на access_token, который в дальнейшем и используем для работы с ресурсами какого-либо сервиса.

Рассмотрим пример авторизации в сервисе Google с помощью OAuth.

1. Регистрация клиентского приложения.

Прежде всего нам необходимо зарегистрировать наше приложение в Google. Для этого необходимо перейти по ссылке. Нажать большую синюю кнопку:

not_created

И в открывшейся форме задать необходимые параметры клиентского приложения. Для настольных приложений необходимо в разделе “Application Type” указать “Installed application”:

new_client

Жмем “Create client ID” и Google выдаст для нашего клиента три параметра:

  • Client ID – id нашего клиента
  • Client secret – секретный ключ нашего приложения
  • Redirect URIs – строка, содержащая URL для редиректа. Для настольных приложений строка всегда имеет вид: urn:ietf:wg:oauth:2.0:oob

 

Теперь, используя эти параметры мы можем получать доступ к ресурсам API Google. Создадим небольшой класс для авторизации.

2. Класс для OAuth-авторизации в Google

Итак, назовем наш класс – TOAuth. Какие свойства он должен содержать? Во-первых, это параметры нашего клиентского приложения – Client ID и Client Secret. Т.к. Redirect URLs никогда не меняется, то зададим это значение как константу.

Далее, согласно спецификации OAuth токен мы будем получать на определенный ресурс, т.е. мы должны предусмотреть хранение название этого ресурса в объекте, назовем свойство как это принято – Scope.

Таким образом, заготовка для модуля нашего будущего класса OAuth будет выглядеть следующим образом:

const
  redirect_uri='urn:ietf:wg:oauth:2.0:oob';
 
type
  TOAuth = class
  private
    FClientID: string;//id клиента
    FClientSecret: string;//секретный ключ клиента
    FScope   : string;//точка доступа
    procedure SetClientID(const Value: string);
    procedure SetScope(const Value: string);
  public
    constructor Create;
    destructor destroy; override;
    property ClientID: string read FClientID write SetClientID;
    property Scope   : string read FScope write SetScope;
    property ClientSecret: string read FClientSecret write FClientSecret;
end;

 

Теперь обратимся к документации Google и посмотрим как получается значение токена. На первом шаге нам необходимо сформировать URL, перейдя по которому пользователь введет в форме свой логин и пароль и подтвердит, что он предоставляет доступ нашему клиенту к ресурсам своего аккаунта. В ответ Google выдаст пользователю код доступа, который должен быть передан в наш класс. Этот код мы и поменяем у Google на действующий в течение часа токен. Реализуем этот алгоритм в нашем классе. Вначале пишем функцию, которая будет возвращать нам URL для перехода пользователя:

function TOAuth.AccessURL: string;
begin
  Result:=Format(oauth_url,[ClientID,redirect_uri,Scope]);
end;

 

Здесь oath_url — это константа вида:

oauth_url = 'https://accounts.google.com/o/oauth2/auth?client_id=%s&redirect_uri=%s&scope=%s&response_type=code';

 

После того, как пользователь перейдет по этому URL он увидит, что-то типа:

access

В “More Info”, кстати, находится сведения о разработчике. Ничего сверхсекретного, никаких адресов сайтов типа http://core-2.ru, исключительно e-mail для связи с разработчиком приложения.  Нажав “Allow access” пользователь получит код:

access2

Этот код пользователь должен скопировать и передать нашему клиенту. Добавим в класс новое свойство – ResponseCode, которое будет хранить этот код.

Следующим шагом будет отправка этого кода в Google и получение токена. Отправка производится обычным образом – через POST-запрос. Ответом будет служить JSON-объект, содержащий необходимые нам данные. Пишем вначале метод отправки запроса и получение ответа в виде строки:

function TOAuth.SendRequest(URL: string; Params: TStream): string;
var Data: TStringStream;
begin
  if Params=nil then Exit;
  with THTTPSend.Create do
    begin
      MimeType:='application/x-www-form-urlencoded';
      Document.LoadFromStream(Params);
      if HTTPMethod('POST',URL) then
        begin
          Data:=TStringStream.Create();
          try
            Data.LoadFromStream(Document);
            Result:=Data.DataString;
          finally
            Data.Free;
          end;
        end
      else
        Result:='';
    end;
end;

 

Теперь мы можем, используя метод SendRequest отправить запрос и получить в ответ текст в формате JSON, содержащий необходмые параметры, а именно:

  • acess_token — токен доступа к ресурсу
  • expires_in — время жизни токена
  • refresh_token — токен для обноления access_token.

 

Чтобы достать значения этих параметров из ответа сервера напишем следующую функцию:

function TOAuth.ParamValue(ParamName, JSONString: string): string;
const StripChars : set of char = ['"',':',','];
var i,j:integer;
begin
  i:=pos(LowerCase(ParamName),LowerCase(JSONString));
  if i>0 then
    begin
      for j:= i+Length(ParamName) to Length(JSONString)-1 do
        if not (JSONString[j] in StripChars) then
          Result:=Result+JSONString[j]
        else
          if JSONString[j]=',' then
            break;
    end
  else
    Result:='';
end;

 

Функция возвращает значение параметра из документа JSONString по его имени ParamName. Теперь добавляем в наш класс необходимые свойства:

  property Access_token: string read FAccess_token write SetAccess_token;
  property Expires_in: string read FExpires_in write SetExpires_in;
  property Refresh_token:string read FRefresh_token write SetRefresh_token;

 

И пишем процедуру получения токена по коду, полученному от пользователя:

function TOAuth.GetAccessToken: string;
const tokenurl='https://accounts.google.com/o/oauth2/token';
      tokenparams = 'client_id=%s&client_secret=%s&code=%s&redirect_uri=%s&grant_type=authorization_code';
var Params: TStringStream;
    Response:string;
begin
  Params:=TStringStream.Create(Format(tokenparams,[ClientID,ClientSecret,ResponseCode,redirect_uri]));
  try
    Response:=SendRequest(tokenurl,Params);
    Access_token:=ParamValue('access_token',Response);
    Expires_in:=ParamValue('expires_in',Response);
    Refresh_token:=ParamValue('refresh_token',Response);
    Result:=Access_token;
  finally
    Params.Free;
  end;
end;

 

Функция возвращает Access_Token и присваивает значения свойствам класса. Соответственно, если нам необходимо обновить токен, то метод обновления может выглядеть так:

function TOAuth.RefreshToken: string;
const crefreshtoken = 'client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token';
var Params: TStringStream;
    Response: string;
begin
  Params:=TStringStream.Create(Format(crefreshtoken,[ClientID,ClientSecret,Refresh_token]));
  try
    Response:=SendRequest(tokenurl,Params);
    Access_token:=ParamValue('access_token',Response);
    Expires_in:=ParamValue('expires_in',Response);
    Result:=Access_token;
  finally
    Params.Free;
  end;
end;

 

Теперь остается продемонстрировать работу класса на каком-нибудь примере.

2. Пример использования класса TOAuth.

Для примера, получим доступ к календарям Google. Создадим новое приложение как показано на рисунке:

TestApp

Справа на форме расположен TWebBrowser в котором мы будем показывать пользователю страницу для авторизации и предоставления доступа.

Пишем обработчик события для кнопки “Получить код”:

var
  ...
  OAuth: TOAuth;
 
implementation
 
procedure TForm2.Button2Click(Sender: TObject);
begin
  OAuth:=TOAuth.Create;
  OAuth.ClientID:=Edit1.Text;
  OAuth.ClientSecret:=Edit2.Text;
  OAuth.Scope:=Edit3.Text;
  WebBrowser1.Navigate(OAuth.AccessURL);
end;

 

Теперь обработчик для кнопки «Получить токен»:

procedure TForm2.Button1Click(Sender: TObject);
begin
  OAuth.ResponseCode:=Edit4.Text;
  Memo1.Lines.Add('Access Token = '+OAuth.GetAccessToken);
  Memo1.Lines.Add('Eexpires_in = '+OAuth.Expires_in);
  Memo1.Lines.Add('Refresh Token = '+OAuth.Refresh_token);
end;

 

и для кнопки «Обновить токен»:

procedure TForm2.Button3Click(Sender: TObject);
begin
  Memo2.Lines.Add(OAuth.RefreshToken)
end;

Теперь можно запустить приложение и убедиться, что мы можем авторизоваться в сервисе и получить токен для дальнейшей работы. Точка доступа к календарям: https://www.google.com/calendar/feeds/default/owncalendars/full

Теперь попробуем получить какую-нибудь информацию от сервиса календарей, используя полученный токен. Для примера попросим Google выдать нам список календарей пользователя.

Как и в случае с ClientLogin токен будем передавать в заголовках. Функция получения XML-документа со списком календарей может выглядеть следующим образом:

procedure TForm2.Button4Click(Sender: TObject);
var HTTP:THTTPSend;
begin
 HTTP:=THTTPSend.Create;
 try
 HTTP.Headers.Add('Authorization: OAuth '+OAuth.Access_token);
 HTTP.Headers.Add('GData-Version: 2');
 if HTTP.HTTPMethod('GET','https://www.google.com:443/calendar/feeds/default/allcalendars/full') then
   Memo2.Lines.LoadFromStream(HTTP.Document);
 finally
   HTTP.Free;
 end;
end;

 

При выполнении этой процедуры Google, как это у него водится, вернет вначале вам перенаправление, поэтому запрос надо будет повторить дважды — вначале как показано выше в листинге, а во втором случае с теме же заголовками, но с URL, который вернет Google. После этого Вы получите в распоряжение XML-документ, содержащий список календарей пользователя.

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
3 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Roman
08/11/2011 18:40

  if HTTPMethod(‘POST’,URL) then — возвращает false!

trackback

[…] был взят класс для работы с Google OAuth о котором я рассказывал в блоге некоторое время назад, но со следующими […]

trackback

[…] несколько мануалов по OAuth 2.0. Ну или прочитать пост «Google API в Delphi. OAuth для Delphi-приложений» в моем блоге, чтобы иметь хотя бы небольшое […]