Авторский материал

OAuth 2.0 авторизация Google из 1С

Данная статья является напоминалкой для получения токена в сервисе Google (v3) с целью дальнейшей работы с Google api.

Документация Google, честно говоря, не порадовала, очень много текста, много разных ссылок об одном и том же с разными вариантами запросов, разные версии документации, разные разделы…

Очень хочется всегда просто открыть интернет, найти толковую статью, и следуя описанным в ней шагам, получить желаемый результат. Но по данной теме не много статей для 1с, полного мануала в одном месте найти не удалось. Методом проб и ошибок, скрещиванием описаний из разных источников удалось выявить последовательность действий. Ею я и хочу поделиться.

Появилась, казалось бы, простая задача – скачать прайс-лист поставщика из Google документа. Задача простая в случае, если id документа постоянный. В этом случае она решается простым HTTP запросом, получением данных HTML и их последующей обработкой (пример выложу позже, в отдельной статье).

Но в нашем случае поставщик регулярно изменяет id файла, поэтому прежде чем получить данные, понадобилось узнать его id на текущий момент.

Задача осложнена тем, что большая часть примеров для 1с написана под v2, а текущая версия v3. Методы отличаются. Версия 2 будет жить еще какое-то время, но в итоге она будет отключена, поэтому лучше сразу брать за основу текущую версию, чтобы потом не переделывать.

Описание методов v3 находится тут: https://developers.google.com/drive/api/reference/rest/v3?hl=ru

Первый момент, который сразу вызвал кучу вопросов – мне надо скачать ЧУЖУЮ таблицу – зачем мне подключаться к СВОЕМУ аккаунту Google? Ответ оказался прост, когда мы заходим в свой акаунт гугл диска, у нас есть раздел «Доступные мне». Как только мы один раз открыли из диска чужую таблицу, она становится нам доступна для скачивания.

Таким образом, вся работа должна строиться именно через подключение к СВОЕМУ диску. А для этого необходимо сначала пройти механизм авторизации.

А тут оказалось уже все не просто.

В этом случае нужно:

1 Завести аккаунт GOOGLE

2 Создать проект на страничке  https://console.developers.google.com/cloud-resource-manager

При добавлении проекта требуется обязательный параметр redirect_uris, там можно указать значение http://localhost – он понадобится в дальнейшем для получения токена.

3 Добавить приложения Google Drive API и Google Sheets API (для возможности чтения таблиц через api, а не через разбор HTML кода)

Если мы хотим грузить именно таблицы в формате Google документа, то добавляем второе приложение. Если нам достаточно просто скачивать файлы другого формата, то можно добавить только Google Drive API. Но мы будем добавлять сразу два разрешения и получать токен сразу на две области.

4 На закладке Credentials добавить разрешение OAuth 2.0 Client IDs

При создании мы получим два важных ключа:

Client и Client secret — Эти ключи нужно сохранить в 1С -они констатны и могут потребоваться при различных запросах.

Дальше начинается магия.

Вся авторизация сводится к тому, чтобы получить еще два ключа:

refresh_token – это константа, его нужно запомнить и сохранить в базе. Меняться он не будет, но будет крайне необходим для получения временного токена

access_token – это временный токен при помощи которого будем получать все необходимые данные запросами. Время жизни токена 1час. После того, как время заканчивается, токен нужно обновлять.

5 Получить код авторизации (одноразовый)

Вспоминается фраза – «чтобы продать что-нибудь ненужное, нужно сначала купить что-нибудь ненужное»

И вот мы получаем что-то ненужное, чтобы обменять его на что-то нужное )))

Описание запроса для авторизации находится тут https://developers.google.com/identity/protocols/oauth2/web-server?hl=ru

Чтобы получить нужные токены, нужно сначала получить единоразово Код авторизации (AUTH_CODE).

Ну а так как он нужен всего один раз, то и заморачиваться писать код на получение данных, не вижу смысла. Воспользуемся любым браузером.

Составляем строку запроса (без символов переноса строки, единой строкой)

https://accounts.google.com/o/oauth2/v2/auth

?scope=https://www.googleapis.com/auth/drive //Области из списка ниже

&access_type=offline //Просто текст

&include_granted_scopes=true //Просто текст

&response_type=code //Просто текст

&redirect_uri=https%3A//oauth2.example.com/code //http://localhost

&client_id=client_id //Переменная client_id

scope — область на которую хотим получить разрешение. Если нужно задать несколько областей, то вводим через пробел

Нас пока интересуют две области, подключенные ранее:

https://www.googleapis.com/auth/drive

https://www.googleapis.com/auth/spreadsheets

Список областей перечислен тут: developers.google.com/identity/protocols/googlescopes
access_type — тип доступа. Для получения токенов без участия пользователя используем значение offline. Также возможно значение online, но при его выборе необходимо будет каждый раз запрашивать разрешение у пользователя в браузере.

Строка будет выглядеть следующим образом – меняем параметр client_id на свой:

https://accounts.google.com/o/oauth2/v2/auth? scope=https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/spreadsheets&access_type=offline&include_granted_scopes=true&redirect_uri=http://localhost&response_type=code&client_id=***-****.apps.googleusercontent.com

Открываем браузер, и вставляем полученную строку в браузер. Если все параметры указаны верно, то программа запросит выбрать аккаунт для подтверждения и запросит разрешения, с которыми нужно будет согласиться.

Если видим ошибку, проверяем 1 правильность написания параметров строки

2 Проверяем, что у нас подключены нужные области и разрешения (на примере Google таблиц)

Если нужные галочки не стоят, устанавливаем, сохраняем, и снова пробуем ввести строку авторизации в браузер.

*Есть еще один момент, не знаю влияет он или нет, но там же дальше выходит предупреждение: «Пока статус публикации установлен на «Тестирование», доступ к приложению имеют только тестовые пользователи».

На всякий случай в список тестовых пользователей был добавлен владелец домена. После этого при первом тестировании строка заработала.

Если все сработало с первого раза, радуемся и идем дальше.

Так как у нас был указан адрес перенаправления http://localhost, то естественно страница не откроется, но щелкнув по адресной строке браузера мы увидим интересующий нас AUTH_CODE. Он будет выглядеть примерно так:

4/iLcXnhpU8NvMHT5aTy8JjXhcROERzkvKq********.

Копируем полностью получившуюся строчку и достаем из нее код

http://localhost/?code=4/0AeaYSHC4EB_*****&scope=https://www.googleapis.com/auth/drive%20https://www.googleapis.com/auth/spreadsheets

Он будет располагаться между «code=» и &scope=

Браузер больше не нужен, можно его закрыть. Переходим в 1С.

6 Получить REFRESH ТОКЕН

Теперь уже пишем код в 1с на получение токена.

Это будет POST запрос с обязательным заголовком («Content-Type»,»application/x-www-form-urlencoded»)

Все параметры должны быть в теле запроса, предварительно закодированы в URL формат

https://oauth2.googleapis.com/token

Пример параметров:

?code=4/iLcXnhpU8NvMHT5aTy8JjXhcROERzkvKq********

&client_id= *****um6.apps.googleusercontent.com

&client_secret=************

&redirect_uri=http://localhost

&grant_type=authorization_code //Просто текст

КОД ДЛЯ ПОЛУЧЕНИЯ REFRESH ТОКЕНА

//Используем переменные, которые вы храните где-то в 1с

// Client_id и client_secret

//и одноразовый AUTH_CODE , полученный на шаге 5. Его хранить смысла нет, он аннулируется сразу после выполнения 6 пункта

СтрокаПараметров = » code=» + AUTH_CODE+ » &client_id=»+ Client_id+»&client_secret=»+ Сlient_secret+»& redirect_uri=http://localhost&grant_type=authorization_code «;

// code — AUTH_CODE из 5 пункта; grant_type= authorization_code – пишем текстом, ничего не меняем

Данные = КодироватьСтроку(СтрокаПараметров, СпособКодированияСтроки.URLВКодировкеURL);

 

Соединение = Новый HTTPСоединение(«www.googleapis.com»,443,,,,,Новый ЗащищенноеСоединениеOpenSSL());

НТТРЗапрос = Новый HTTPЗапрос(«/oauth2/v4/token»);

НТТРЗапрос.Заголовки.Вставить(«Content-Type», «application/x-www-form-urlencoded»);//Обязательный

НТТРЗапрос.УстановитьТелоИзСтроки(Данные,КодировкаТекста.UTF8);

HTTPОтвет = Соединение.ВызватьHTTPМетод(«POST», НТТРЗапрос);

Содержимое = HTTPОтвет.ПолучитьТелоКакСтроку();

ЧтениеJSON = Новый ЧтениеJSON;

ЧтениеJSON.УстановитьСтроку(Содержимое);

Попытка

РезультатЧитаемый = ПрочитатьJSON(ЧтениеJSON,Истина);

Исключение

//Оповещаем себя о неудаче )

Возврат Неопределено;

КонецПопытки;

//Refresh ТОКЕН

RefreshТокен = РезультатЧитаемый.Получить(«refresh_token»);

В ответ будет получена строка в формате JSON следующего вида:

{«access_token»: «ya29.a0Ad52N3-***** «,

«expires_in»: 3599,

«refresh_token»: «1//0cGeZsBnZ-***_-_***»,

«scope»: «https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/drive», token_type»: «Bearer»}

access_token, полученный в данном запросе будет актуален 1 час, затем он действовать перестанет, поэтому нам обязательно будет нужен шаг 8

7 Фиксируем refresh_token – он постоянный , его нужно сохранить в 1С, он будет нужен постоянно.

8 Получаем Access Токен (действует час) – данную процедуру нужно будет повторять каждый раз, когда при обращении к серверу, он будет возвращать в заголовке «WWW-Authenticate» текст «invalid_token».

//Используем переменные, которые вы храните где-то в 1с

// Client_id , Сlient_secret и Refresh_token

КОД ДЛЯ ПОЛУЧЕНИЯ ACSESS ТОКЕНА

СтрокаПараметров = «client_id=»+ Client_id

+»&client_secret=»+ Сlient_secret

+»&refresh_token=»+ Refresh_token

+»&grant_type=refresh_token»;

 

Данные = КодироватьСтроку(СтрокаПараметров, СпособКодированияСтроки.URLВКодировкеURL);

Соединение = Новый HTTPСоединение(«www.googleapis.com»,443,,,,,Новый ЗащищенноеСоединениеOpenSSL());

НТТРЗапрос = Новый HTTPЗапрос(«oauth2/v4/token»);

НТТРЗапрос.Заголовки.Вставить(«Content-Type», «application/x-www-form-urlencoded»);

НТТРЗапрос.УстановитьТелоИзСтроки(Данные,КодировкаТекста.UTF8);

HTTPОтвет = Соединение.ВызватьHTTPМетод(«POST», НТТРЗапрос);

Содержимое = HTTPОтвет.ПолучитьТелоКакСтроку();

ЧтениеJSON = Новый ЧтениеJSON;

ЧтениеJSON.УстановитьСтроку(Содержимое);

Попытка

РезультатЧитаемый = ПрочитатьJSON(ЧтениеJSON,Истина);

Исключение

//Оповещаем себя о неудаче )

Возврат Неопределено;

КонецПопытки;

//НОВЫЙ ТОКЕН

НовыйТокен = РезультатЧитаемый.Получить(«access_token»);

В ответ будет получена строка в формате JSON следующего вида:

{«access_token»: ya29.a0Ad52N3-*****

«expires_in»: 3599,

«scope»: «https://www.googleapis.com/auth/drive»,

«token_type»: «Bearer»

}

access_token сохраняем в 1С и используем до того момента, пока не закончится срок его действия.

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

Строка «token_type»: «Bearer» означает, что в дальнейшем при обращении к серверу Google в заголовке должна передаваться строка Bearer с пробелом + Новый токен

НТТРЗапрос.Заголовки.Вставить(«Authorization»,»Bearer «+ НовыйТокен);

Теперь жизнь стала немного проще. Для дальнейшей работы нам требуется только периодически получать новый токен при помощи refresh_token и вставлять его в заголовок НТТРЗапроса.

9 Получение списка доступных мне документов (это уже для самой задачи)

КОД НА ПОЛУЧЕНИЕ ID ДОСТУПНЫХ ДОКУМЕНТОВ

лЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();

лНТТРСоединение = Новый HTTPСоединение(«www.googleapis.com»,,,,,,лЗащищенноеСоединение);

лНТТРЗапрос = Новый HTTPЗапрос(«/drive/v3/files»);

лНТТРЗапрос.Заголовки.Вставить(«Authorization»,»Bearer «+ Access_token); //Подстваляем свое значение Access_token

Попытка
лHTTPОтвет = лНТТРСоединение.ВызватьHTTPМетод(«GET», лНТТРЗапрос);

Исключение

//Оповещаем себя о неудаче )

КонецПопытки;

лТекстОтвета = лHTTPОтвет.ПолучитьТелоКакСтроку();

 

Если лHTTPОтвет.КодСостояния <> 200 Тогда //Есть ошибки

//Получим ответ

лВариантОтвета = лHTTPОтвет.Заголовки.Получить(«WWW-Authenticate»);

Если лВариантОтвета <> Неопределено И СтрНайти(лВариантОтвета,»invalid_token») > 0 Тогда

Возврат «Необходимо обновление токена»; //По этому ответу дергаем функцию обновления токена, и вызываем запрос еще раз уже с новым токеном

Иначе

//Оповещаем себя о неудаче )

КонецЕсли;

КонецЕсли;

Текстом ответа будет Json, из которого мы без труда уже сможем получить id интересующих нас документов

{

«kind»: «drive#fileList»,

«incompleteSearch»: false,

«files»: [

{

«kind»: «drive#file»,

«mimeType»: «application/vnd.google-apps.spreadsheet»,

«id»: «2f3ZUQGOWWHVqycyStWF7YXcsfywgauNeLZRa_DZMjTM»,

«name»: «Новая таблица»

},

{

«kind»: «drive#file»,

«mimeType»: «application/vnd.openxmlformats-officedocument.spreadsheetml.sheet»,

«id»: «1C6oGinRFD_JNEyGSGtUBZy9RyYLqfU7W»,

«name»: «наличие на складе на 19.04.24.xlsx»

},

{

«kind»: «drive#file»,

«mimeType»: «application/pdf»,

«id»: «1rlqPYhR85aYhjqeWQY4scIQXkKmPKCyb»,

«name»: «Catalog товаров.pdf»

}

]

}

Таким образом задача решена, идентификаторы получены.

Еще раз хочется добавить, что в данном списке видны документы ЧУЖИХ дисков, выложенные для скачивания. (PS ID изменены, поэтому пытаться скачивать их смысла нет)

Если на диске лежит обычный файл, то скачать его можно через запрос вида https://www.googleapis.com/drive/v3/files/{fileId}?alt=media

Поделиться в соцсетях
Показать больше
Подписаться
Уведомление о
guest
0 Комментарий
Встроенные отзывы
Посмотреть все комментарии
Back to top button