Пока в интернете я встречал только описание использования из 1С "Трехногого OAUth" (three-legged OAuth), где вызов API идет от имени конечного пользователя и обычно требуется подтверждение пользователя. Способ на мой взгляд длинноватый, поэтому я решил вызвать из 1Ски по-человечески двуногую авторизацию: "two-legged OAuth," или "2LO". Делал на платформе 8.3.10.2168, протестировал также на 8.3.11.3034. Добавлено 17.07.2024: вариант обработки для платформы 8.3.9 (проверено на 8.3.9.2033 и 8.3.9.2233)
Речь идет о модели авторизации, описанной:
краткое описание с картинкой — https://developers.google.com/identity/protocols/OAuth2#serviceaccount
подробное — https://developers.google.com/identity/protocols/OAuth2ServiceAccount
Этот способ требует создания и криптографического подписывания JSON Web Tokens (JWT). На данный момент встроенным Менеджером Криптографии 1ска не умеет подписывать SHA256 хеш, а гугл другого не приемлет. Изначально я использовал COM-объект System.Security.Cryptography.RSACryptoServiceProvider. Он работал как надо, но смущало, что в документации не написано, что он так умеет (в опциях метода SignHash отсутствует вариант SHA256). Для гарантии, что будет работать на другом компьютере, я решил вычислить цифровую подпись "вручную" обычной арифметикой, которую достойно выдержала 1С. Примечательно, что при этом она оперирует десятичными 309-значными числами, и подпись вычисляет за пару секунд. Триста девять — это не опечатка, вот например, значение одной из переменных типа Число, используемых при вычислении:
502 980 391 062 131 532 641 704 729 356 208 435 540 985 711 615 837 230 131 224 218 031 451 499 103 580 000 500
042 512 824 109 317 254 211 102 144 888 404 960 708 248 565 484 714 907 166 675 270 791 229 966 881 267 979 216
170 431 549 149 990 776 636 979 550 241 423 110 985 244 106 352 654 087 401 423 069 254 226 452 760 694 752 994
636 816 447 756 286 216 072 699 194 804 391 178 250 315 913 588 444 283 437
На 8.3.9 вычисляет дольше, но тоже за приемлемое время — похоже, используются не все ядра процессора.
Обработка получает токен от имени сервисной учетной записи моего тестового проекта. Scope запрашивается только для API spreadsheets. Для демонстрации работоспособности полученного токена, из формы обработки можно изменить столбец тестовой гугл-таблицы, а затем по указанному на форме обработки адресу посмотреть результат.
Для получения токенов на api spreadsheets от имени Вашего сервис-аккаунта, необходимо в консоли разработчика https://console.developers.google.com создать/скачать JSON-ключ сервисного аккаунта с доступом к api spreadsheets, и указать его в поле обработки "Путь файла ключа json". Токен своей учетки Вы получите, но при попытке изменить мою тестовую таблицу с таким токеном гугл вернет error 403 "PERMISSION_DENIED", поскольку у Вашего сервис-аккаунта нет доступа к моей таблице.
При воспроизведении в своей работе аналога продемонстрированного механизма не забудьте прописать нужные Вам "scope" в коде обработки и соответствующие API при запросе у гугла json-ключа. Также не забудьте расшарить доступ к объектам гугла, которые Вы хотите изменять или читать через API. Доступ нужно предоставлять емейлу Вашей сервисной учетной записи. Этот емейл можно найти внутри json ключа, в значении свойства "client_email", либо в моей обработке указать путь к Вашему JSON-ключу и нажать кнопку "разобрать сертификат". Емейл отобразится в поле "Расшарить для емейла".
Важный момент: в операционной системе должно быть правильное время и правильный часовой пояс (используется функция 1с УниверсальноеВремя), иначе обработка запросит у гугла неверные дату начала и окончания срока действия токена, как следствие токен не выдадут, в ответе будет что-то со словом time. Если правильные системное время и пояс устанавливать не хотите — тогда нужно в модуле формы указать свой алгоритм расчета времени для переменной ВремяИстеченияUTC. Учитывайте, что в данной схеме авторизации гугл выдает токены максимум на час, затем нужно получать новый токен.
Для разбирающихся в криптографии. Цифровая подпись арифметически вычисляется с использованием SHA256withRSA (RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function). Для этого в процессе обработки средствами 1С происходит парсинг закрытого RSA-ключа в формате PEM, BASE64 которого содержится в сертификате JSON. На вкладке "Парс сертификата json" в дерево выводится результат парсинга, и в ветке дерева "OCTET STRING" содержится SEQUENCE, в котором перечислены INTEGER — параметры закрытого и открытого ключей: Version, Modulus, publicExponent (Exponent, E), privateExponent (D), prime1 (P), prime2 (Q), exponent1 (dP или d mod (p-1)), exponent2 (dQ или d mod (q-1)), coefficient (InverseQ или InvQ или (inverse of q) mod p).
супер! все работает
а не подскажете как добавлять строку в конец листа?
у меня на такую строку
E/values/Sheet2:append?valueInputOption=USER_ENTERED
/v4/spreadsheets/1u3hBxBn0hHfOOyJ6TjLzsji58SPP3ttNyRN31xTgUk
ругается с кодом 404
а так
E/values/Sheet2?valueInputOption=USER_ENTERED
/v4/spreadsheets/1u3hBxBn0hHfOOyJ6TjLzsji58SPP3ttNyRN31xTgUk
работает, но записывает с начала листа
Здравствуйте. Если нужно добавить новую дополнительную пустую строку (т.е. на странице последняя строка, в которую можно что-то записать была 969я, нужно, чтоб появилась 970я строка), то нужно использовать POST по адресуhttps://sheets.googleapis.com/v4/spreadsheets/spreadsheetId:batchUpdate , при этом в теле нужно передать JSON {«requests»: [ { «appendDimension»: { «sheetId»: sheetId, «dimension»: «ROWS», «length»:1}}]} https://developers.google.com/sheets/api/samples/rowcolumn#append_empty_rows_or_columns
(3) спасибо! поменял HTTPСоединение.Записать на HTTPСоединение.ОтправитьДляОбработки
Отлично!
Конечно же, важно не путать методы HTTPСоединение (HTTPConnection):
Записать (Put)
ОтправитьДляОбработки (Post)
Получить (Get)
Реально работает. Спасибо.
В данном примере сертификат содержится в файле формата JSON. А если сертификат в файле cer, как тогда можно достать закрытый ключ?
(7)В .cer обычно только открытый ключ. Google выдавал еще .p12 — из него ключи можно достать например через powershell.
Ключи и параметры для ускоренного расчета будут видны в файле FromPower.xml, ими можно вычислять цифровую подпись для гугла.
(8) Некорректно сформулировал свой вопрос. Воттут ты используешь COMОбъект(«System.Security.Cryptography.RSACryptoServiceProvider») для подписи файла по алгоритму RSA-sha256. А в обработке из этой темы СОМ-объект не используется. Возможно ли только средствами 1С подписать и поверить подпись RSA-sha256, если сертификат лежит в файле cer?
(9)Если закрытый ключ содержится в файле — думаю можно, т.к. у эски есть инструменты для работы с двоичными данными. Но повторю, в .cer как правило нет закрытого ключа, нужен .pfx или .p12.
(10) pfx тоже есть. Но при экспорте из хранилища сертификатов был запрошен ввод пароля. На Хабре прочитал, что это дополнительная защита закрытого ключа, сам файл pfx шифруется с помощью этого пароля.
Я попробовал разобрать файл cer используя алгоритм из обработки. Но результат получился не корректным. Получились классы не входящие в формат ASN.1
(11)Шифруется потому что содержит закрытый ключ. Значит, если сильно хочется эской — нужно разбирать и расшифровывать ). Посмотрел пару закрытых ключей в pfx — они зашифрованы 3DES SHA-1. Но это совсем для 1с-гурманов ). Менеджер криптографии вроде только с асимметричным шифрованием работает, т.е. придется алгоритм расшифровки вручную прописывать, если хочется без COM или Native.
(12) Ну мы не такие 🙂 . Решили прост отказаться от RSA-sha256. Нам нельзя использовать сторонние библиотеки.
(13)Да, средствами эски расшифровывать закрытый ключ из pfx неоправданно трудоемко будет. Разве что для какой-нибудь дипломной работы — из теоретического интереса решить задачку.
В чем отличие между двумя вложениями?
(15)Здравствуйте! В версии (8.3.9) дописаны некоторые функции для работы с двоичными данными, которые отсутствуют в платформе 8.3.9. Если версию обработки 8.3.9 запустить на более поздних платформах — то будет ругаться из-за конфликта имен функций встроенных в платформу и написанных мной, тогда нужно просто удалить область
(16) Благодарю за ответ и за публикацию
Про SHA256 в 1С, это соответственно АлгоритмХеширования. Что-то у него даже описания нет….
(18)Вы имеете в виду описание в СП МенеджерКриптографии-АлгоритмХеширования-SHA256? Выше в статье я писал «На данный момент встроенным Менеджером Криптографии 1ска не умеет подписывать SHA256 хеш, а гугл другого не приемлет.» В СП его нет, но можно обратиться к любому модулю криптографии Новый МенеджерКриптографии(<ИмяМодуляКриптографии …), потом .
ПолучитьИнформациюМодуляКриптографии(), и в нем есть массив .АлгоритмыХеширования — там найдете полный перечень алгоритмов хеширования, с которыми справится 1С платформенными средствами, SHA256 пока там отсутствует.
Добрый день.
Я немного соптимизировал, как мне кажется, генерацию JSON для передачи на гугл
Во первых, использую метод batchUpdate, он позволяет избавиться от необходимости указания range в url, во вторых ф-я глобального контекста ЗаписатьJSON, позволяет избавиться от вложенного цикла.
Показать
(20)Здравствуйте! Цель этой обработки — получить access token. Гугл-таблица в ней заполняется лишь для проверки работоспособности полученного токена. ЗаписатьJSON и ПрочитатьJSON глобального контекста — да, как правило удобней и лаконичней эти функции использовать.
(21) Да я ж не спорю! Она мне ОЧЕНЬ помогла, хоть и промучился несколько дней из-за невнимательности своей 🙂
Я не вам в упрек ни в коем случае.
(21) Кстати обнаружил неприятный нюанс — Googe Sheet API не понимает JSON-format даты/времени.
Посему, перед применением ЗаписатьJSON приходится все даты конвертить в строки, все в тех же мерзких циклах. 🙁
(22)Я к тому, что вдруг кто будет читать перед тем, как скачать эту обработку. Обработка позволит не тратить время на изучение нудной процедуры получения токена. Плюс она отвязана от операционной системы, работает на линуксе, т.к. не использует обращение к криптопровайдеру через COM для вычисления цифровой подписи, а вычисляет сама чистой арифметикой. Но дальнейшее использование полученного токена — это уже предмет других примеров-обработок.
(23)В спецификации JSON отсутствует дата, отсюда и проблема. Т.е. нету такого понятия, как «JSON-format даты/времени». RFC7159:
Использующие обмен данными в формате JSON сами принимают решение, как передавать даты в форме строки. В 1С есть три встроенных варианта для этого — например в функциях глоб.контекста ПрочитатьДатуJSON(…) ЗаписатьДатуJSON(…) — ISO, JavaScript, Microsoft. В глоб.контекст. ЗаписатьJSON — тоже третьим параметром можно передать настройки сериализаци, в том числе для даты с тремя этими вариантами. Но google sheets api, видимо, какой-то четвертый формат использует )
(25) а вот настройки сериализации я что-то не попробовал, спасибо.
Гугл принимает dd-MM-yyyy HH:mm:ss, если стоит параметр USER_ENTERED, а RAW я не пробовал 🙂
(24) Не, обработка просто шикарная! 100500й раз спасибо вам 🙂 Вы, по-моему вообще единственный кто реализовал 2-leg авторизацию.
(26)
Судя по инструкции гугла, можно и не пробовать ):
USER_ENTERED The values will be parsed as if the user typed them into the UI. Numbers will stay as numbers, but strings may be converted to numbers, dates, etc. following the same rules that are applied when entering text into a cell via the Google Sheets UI.
В JSON либо строка либо число, других вариантов в данном случае нет. И в случае RAW — все останется как есть — строкой или числом.
(26)
А Вам спасибо за отзыв !
(20)
упс. выглядит красиво (я так понял в вывод (начиная с А1 в целевой гугл-таблице) кидается содержимое Масс.
тупой вопрос: а как собственно Масс формируется для таб.документа (или области)?..
спасибо!
тупые (снова, уж извините) вопросы.
а как именно «взаимоувязываются» линк на гугл-таблицу с кодом? в смысле — где и как в коде указывается, что именно эта таблица правится через api?..
(32) о тут уже оказывается отрезан обмен сообщениями — тупо редирект в телегу и прочее (которого у меня нет).
спасибо, добрый человек. надеюсь автор топикстартер извинит за диалог тут.
1) понятно что в константе — непонятно что оно (ТабИД) собой представляет и как его получить…
2) вижу у тебя тупо ТЗ выгоняется в гугль-шит? а как таб.документ?
(32)Нехило Вы этак, весь мой авторский код «криптопровайдера» спалили.
(33)
Мне табДокумент не нужен, я выгружаю в гугль результаты запроса.
Я думаю ТабДок проще гнать сразу в массив, без ТЗ. И, скорее всего, просто циклами.
Я еще почему с ТЗ заморочился и с массивом «по столбцам», у меня выгружается таблица > 50к строк. Гнать ее вложенными циклами, по моему мнению, менее эффективно, чем через «ВыгрузитьКолонку» хотя я и не тестировал. Но! даты приходится конвертировать в строку после выгрузки колонки. Глупый Гугд не принимает дату в ISO.
извините, снова тупые вопросы (пытаюсь пере-до0пилить немного под себя)
1. Проект создан, в «Бибилиотека» подключены API googlesheets и googledrive
2. Учетные параметры выглядят вот так (аттач).
сначала запутался — который json и как выгружать… с горем пополам выгрузил тот, который обработка съела (на другой ругалась).
3. от этой же учетки (в которой создан проект) — создал и сохранил гугль-таблицу. доступ — всем на всё (потом буду экспериментировать с ограничениями, дошло).
4. из джсона — разобрать сертификат — получил для себя мыло (далее использую его).
5. получить токен —
4. для этой гугль-таблицы, с мылом из разобранного сертификата — сгенерировать токен.
5. список листов — получаю запросом с этим токеном+мылом без проблем (с любым токеном, вообще-то — но это наверное из-за полного расшаривания).
6. попытка загнать данные в эту таблицу (на первый лист, с #gid=0) с этими же (своим!) токеном и (своим!) мылом — error 403 «PERMISSION_DENIED».
(36)
прим.: не на токен ругается…
{
«error»: {
«code»: 403,
«message»: «The caller does not have permission»,
«status»: «PERMISSION_DENIED»
}
}
— файл создан под тем аккаунтом, в который выполнен вход, и расшарен максимально, на весь инет (редактирование)
а может где-то в консоли какой-нибудь можно посмотреть — кто лез через апи к файлу?
(37)Думаю, стОит попробовать шаг-в-шаг повторить действия, описанные в статье, т.к. они позволяют редактировать таблицу. А уж потом экспериментировать с доступами «всем на всё» и проч.
(36) Я так думаю в настройках доступа к таблице у тебя не указан в явном виде имейл сервис-аккаунта
(38) Ну таки да, я делал, у меня работает 🙂
Да, еще момент, насколько я понял, учетка в которой живет таблица должна быть для частного лица, иначе все эти АПИ вроде бы платные.
(40)
ааагрррхх… учетка, конечно же (мне ж не для домашней булгахтерии эта вся беда нужна…) — корпоративная…..
(41)
Cthulhu если есть возможность — отпишитесь пжл., действительно ли дело в корпоративной учетке было. Если на корпоративную таблицу дать доступ емейлу корпоративного сервис-аккаунта — то все равно «PERMISSION_DENIED»?
(42) Да, у меня так. я тоже начал с бизнес-учетки.
Потом по итогу просто сделал отдельную «частную».
(42)
отписываюсь.
*** Вошел в личный аккаунт (не корпоративный).
1.1. Создал API-ключ сервисного аккаунта (сохранение json-файла на локал).
1.2. Создал новый гугль-шит, максимально расшарил (доступен всем на все).
2. Запустил обработку (подпиленную, адрес гугль-шита в текстовое поле ввода, e-mail в коде — из поля ввода).
2.1. Выбрал json-файл из п.1.1.
2.2. «Разобрать сертификат», «Получить токен» == «Подпись верна: Да»
2.3. Вбил свой адрес гугль-шита (из п.1.2).
2.4. «Отправить Столбец в гугл» == «Успешно» (и столбец в моем гугл-шите (см.п.1.2) изменился как заказано.
*** Вошел в корпоративный аккаунт.
пп.1.1-2.3, повторил в полном объеме с аналогичными результатами (все Ок).
2.4. «Отправить Столбец в гугл» == { «error»: { «code»: 403, «message»: «The caller does not have permission», «status»: «PERMISSION_DENIED» } }
(39)
я в коде заменил — вместо явного указания он тянется из соответствующего поля ввода (которое пере-вычисляется по «разобрать сертификат»).
(45) Речь не про код 1С, а про доступ в гугле. У таблицы явно должен быть разрешен доступ томы «мылу», что зашито в JSON, при гнереации сервис-аккаунта
(44) Да-да, все точно так. с корпоративной не работает. Денег наверное надо дать. ну или они там дают пробник вроде на год.
(46)
т.е. ты имеешь ввиду, что по мылу, указанному в json-файле API-ключа сервисного аккаунта — нет доступа к API? по-моему это бред, извини…
(48)Имелось в виду, что возможно у API особый подход к разрешениям для сервисных аккаунтов — т.е. возможно «все для всех» на них не всегда распространяется, и например, сервисному емейлу обязательно нужно персональное разрешение на редактирование таблицы. Но, судя по Вашему весьма полезному эксперименту в (44) — проблема была исключительно в «корпоративности» учетки.
(48) сервисной учетке разрешение на Sheets API дано?
Бред или не бред, но у ТС и у меня работает. Значит, надо где-то у тебя искать. Вот мы и пытаемся нащупать проблему.
(50)Уже ведь выяснили, что проблема исключительно в корпоративной учетке, Cthulhu специально для этого эксперимент провел (44). Корпоративку ему отбивало «PERMISSION_DENIED», но когда он сделал из личной учетки — то «и столбец в моем гугл-шите (см.п.1.2) изменился как заказано.»
(50)
в обеих учетках «api включен» для «google drive» и для «google sheets».
(11)Извините, просто памятка. На днях наткнулся, удобная штуковина для разбора ASN.1https://lapo.it/asn1js/
И уж раз начал писать — то в моей обработке — да, я не делал универсальный разбор любых файлов ASN, а ограничился только тем, что было необходимо для разбора json-сертификатов от Гугла.
Кто-то пробовал использовать данный способ получения токена сервисной УЗ для управления корпоративной почтой(возможно в личной аналогично, не пробовал) через GMail API? Чтобы поменять настройки ящика другому человеку(автоответ и подпись) нужно включить domain-wide делегирование. Не совсем понятно, нужно ли при получении токена указывать адрес юзера в поле стурктуры «sub», которому необходимо изменить настройки? Попытка добавление этого поля в структуру запроса токена выдается ошибка ниже. При этом все scope для сервисного аккаунта выданы и без sub все корректно выдается. Но с таким выданным токеном не удается отредактировать чужие настройки.
{
«error»: «unauthorized_client»,
«error_description»: «Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested.»
}
(54)
Note:Operations guarded by this scope are restricted to administrative use only. They are only available to G Suite customers using a service account with domain-wide delegation. Restricted
У Вас есть платный G Suite и domain-wide delegation ?
(55)
да, платный GSuite и включенное делегирование в проекте и сервисной УЗ.
Как раз этот scope и API пробую использовать.