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.
Дальше либо сохраняем токен куда-нибудь, либо каждый раз будем так запрашивать – при наличии выданного токена запроса на доступ к данным не будет, просто на несколько секунд будет выскакивать окно браузера.
Авторизация и получение доступа к api
Один из ключевых моментов реализации любого API — авторизация пользователя. Как уже было сказано ранее, в настоящее время наиболее активно используется авторизация пользователей по протоколу OAuth, а точнее — OAuth 2.0.
Чтобы авторизовать пользователя по OAuth вы можете написать свой собственный класс или же, если Вы используете Delphi XE5-XE7, то можете воспользоваться компонентами REST Client Library. Чтобы не повторяться о том, как это сделать, я просто приведу здесь ссылки на статьи где рассматривалась авторизация по OAuth в разных онлайн-сервисах:
- Серия статей про OAuth в Google:
- Google API в Delphi. OAuth для Delphi-приложений,
- Google API в Delphi. Обновление модуля для OAuth,
- Решение проблем с Google OAuth 2.0. для Win-приложений,
- Тестирование запросов к API Google средствами Delphi. Компонент OAuthClient для Delphi XE — XE3.
- Использование REST Client Library для OAuth:
- Delphi XE5: REST Client Library,
- Delphi: авторизация по OAuth 2.0 в Dropbox своими силами,
- REST Client Library: использование API ВКонтакте
Однако встречаются и такие API в которых авторизация пользователя проводится по собственным протоколам и правилам. В этом случае вам необходимо самостоятельно реализовать процедуру авторизации (для чего необходимо знать всё то, о чем сказано в первой части статьи). Рассмотрим пример работы с подобными API.
Выполнение взаимосвязанных методов
Чтобы закрепить материал, реализуем ещё пару связанных методов — когда от результата выполнения одного метода (или от значения какого-либо параметра из данных предыдущего запроса) зависит результат выполнения другого.
Например, попробуем получить список исполнителей и подробную информацию по выбранному пользователю. Если мы не можем получить список, то следовательно и получить подробную информацию по отдельному пользователю мы не получим. Если мы не получим из списка верные значения свойств объекта пользователя, то и результатом выполнения связанного метода будет ошибка.
Выполнение запросов к api
Выполнив авторизацию и получив доступ к API мы можем выполнять различные запросы к API. Различные API требуют могут предъявлять разные требования к выполнению запросов. И прежде, чем начинать писать код в Delphi, опять же, следует внимательно прочитать документацию к API и определиться с тем как могут выглядеть различные запросы к одному и тому же API.
В URL запроса всегда присутствует общая для всех запросов часть. Так, например, если используется API, использующий REST-принципы (любой API Яндекса, Google, ВКонтакте и т.д.), то запросы к такому серверу могут иметь следующий вид:
Парсинг результатов запроса
На предыдущем шаге работы с API мы получили от сервера «сырые» для будущего приложения данные. То есть на данный момент ни наше приложение ни наш класс для работы с API «не знают» что делать с данными — это простая строка, которую необходимо правильно разобрать и представить пользователю приложения.
В своей работе с самыми различными API я придерживаюсь следующих двух положений: