воскресенье, 2 июля 2017 г.

Delphi 10.2 Tokyo и доступ к Яндекс.Диск через REST API. Часть 1 - получение токена

После атак WannaCry и Petya задумался о необходимости своего бэкапера, который бы потихоньку сливал данные на Яндекс.Диск.
Причины:
1. Как-то с Яндексом дешевле и проще работать, чем с Гуглом. Видимо, звание "корпорации зла" скоро перейдет от мелкомягких к суперматематикам
2. Штатная программа от Яндекс.Диск не отличается нужным уровнем интеллекта именно в плане бекапа пользовательских данных. Ей чего залили в папке, то она и засинхронизировала. Зашифровали файл? Значит и в облаке надо синхронизировать...
3. Ну и документация у Яндекса по русски и доходчиво по шагам описана. В гугле же пока что-то найдешь - опухнешь, не математик я, все же...

Ну хватит лирики.
Инструментарий: Embarcadero Delphi 10.2 Tokyo, компонент  OAuth2Authenticator.
Документация: REST API Yandex.Disk, вдохновление (устаревшее) на тему использования Google Drive
Этапы: Чтение документации с парралельным ваянием проекта.
Итак, начинаем.
На форму кидаем все четыре вышеуказанных компонента, TMemo для отладки, TSpeedButton. В uses interface добавляем вручную REST.Authenticator.OAuth.WebForm.Win, System.StrUtils, System.Types.
В форму добавляем методы

  public
    { Public declarations }
    procedure TitleChanged(const ATitle: string;  var DoCloseWebView: boolean);
    procedure AfterRedirect(const AURL: string; var DoCloseWebView : boolean);

и создаем реализации этих методов

procedure TForm3.AfterRedirect(const AURL: string; var DoCloseWebView: boolean);
begin
  Memo1.Lines.Add('after redirect to '+AURL);
end;


procedure TForm3.TitleChanged(const ATitle: string;
  var DoCloseWebView: boolean);
begin
  Memo1.Lines.Add('== '+ATitle);

end;
procedure TForm3.SpeedButton1Click(Sender: TObject);
var wf: Tfrm_OAuthWebForm;
begin
  //создаем окно с браузером

  //для перенаправления пользователя на страницу Яндекс
  wf:=Tfrm_OAuthWebForm.Create(self);
  try
    //определяем обработчик события смены Title
    wf.OnTitleChanged:=TitleChanged;
    wf.OnAfterRedirect:=AfterRedirect;
    //показываем окно и открываем
    //в браузере URL с формой подтверждения доступа
    wf.ShowModalWithURL(OAuth2Authenticator1.AuthorizationRequestURI);
  finally
    FreeAndNil(wf);
  end;
end;



для чего все это? Пока для отладки.

Теперь задумаемся - надо как-то обозвать приложение и зарегистрировать его в Яндекс.OAuth
Придумываем название и регистрируем его. Процесс регистрации очень хорошо описан в документации, поэтому повторять его не буду. Единственное - Callback URL пишем https://localhost
После регистрации приложения получаем его ID и пароль, который нам потребуется дальше для получения токена.




Переключаемся в Delphi. Дважды щелкаем на OAuth2Authenticator, или правой кнопкой - Configure и заполняем поля





При таком заполнении сформируется  правильный URL для запроса кода подтверждения.
Жмем Apply, запускаем программу и жмем на кнопку.
Выскакивает окно браузера, в котором, возможно, потребуется войти в учетную запись Яндекса. У меня вход уже произведен.

Нажимаем на "Разрешить" и вот тут наблюдаем следующее - яндекс пытается отредиректить  на https://localhost

и, как мы видим, в ссылке есть код подтверждения.

Итак, вся нужная информация поступает в обработчик AfterRedirect. Исходя из этого переписываем обработчик следующим образом

procedure TForm3.AfterRedirect(const AURL: string; var DoCloseWebView: boolean);
var Str:String;
    StrArr:TStringDynArray;
begin
  Memo1.Lines.Add('after redirect to '+AURL);
  if StartsText('https://localhost',AURL) then begin
    DoCloseWebView:=true;
    //разбиваем строку
    StrArr:=SplitString(AURL,'?=&');
    Str:=StrArr[1];
    if Str='code' then begin
      // и делаем запрос на получение токена
      // код подтверждения во втором элементе
      OAuth2Authenticator1.AuthCode:=StrArr[2];
      OAuth2Authenticator1.ChangeAuthCodeToAccesToken;
      Memo1.Lines.Add(OAuth2Authenticator1.AccessToken);
      Memo1.Lines.Add(OAuth2Authenticator1.RefreshToken);
Memo1.Lines.Add(DateTimeToStr(OAuth2Authenticator1.AccessTokenExpiry));
    end;
    if Str='error' then begin
      // обрабатываем ошибку
      if StrArr[2]='access_denied' then
        ShowMessage('Отказ в предоставлении доступа');
      if StrArr[2]='unauthorized_client' then
        ShowMessage('Приложение заблокировано, либо ожидает модерации');
    end;
  end;
end;

Все!
Теперь опять запускаем программу, жмём кнопку и просто получаем токен!


Выделенные желтым - токен, refresh-токен и время окончания действия токена. Соответствующие значения находятся в свойствах компонента OAuth2Authenticator.

Дальше либо сохраняем токен куда-нибудь, либо каждый раз будем так запрашивать - при наличии выданного токена запроса на доступ к данным не будет, просто на несколько секунд будет выскакивать окно браузера.


1 комментарий: