chuanyurug
@chuanyurug
Системная аналитика, веб-дизайн

Как использовать сервисный аккаунт в Google Apps Script для непрямого доступа пользователей к Google-таблице?

Я пытаюсь сделать веб-приложение на Google Apps Script с использованием сервисного аккаунта, чтобы не давать пользователям прямого доступа к одной из Google-таблиц, которую я использую в качестве базы данных. Я создал сервисный аккаунт в консоли Google Cloud и добавил email сервисного аккаунта редактором таблицы базы данных. В проекте Apps Script подключил библиотеку OAuth 2 и сервис Google Sheets API.
Для начала протестировал авторизацию и запись данных в другую таблицу, к которой дал доступ тестовому пользователю. Сделал шаблон HTML:

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <h1>Hello</h1>
    <p>You are logged in as <?= activeUser ?></p>
  </body>
</html>


И прописал следующий код:
function doGet() {
  const htmlTemplate = HtmlService.createTemplateFromFile("index");
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const ws = ss.getSheetByName("Logs");
  const activeUser = Session.getActiveUser().getEmail();
  const effectiveUser = Session.getEffectiveUser().getEmail();
  htmlTemplate.activeUser = activeUser;
  const htmlService = htmlTemplate.evaluate();
  ws.appendRow([activeUser,effectiveUser]);
  return htmlService;
}


Развернул приложение с параметрами:
Execute as: User accessing the web app
Who has access: Anyone with Google account


Результат: тестовый пользователь после авторизации попал на страницу `main` и увидел свой email.

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

function getSheetsAuthService() {
  var service = OAuth2.createService('sheetsAuthService')
  .setTokenUrl('https://accounts.google.com/o/oauth2/token')
  .setPrivateKey("PRIVATE_KEY")
  .setClientId('EMAIL')
  .setScope('https://www.googleapis.com/auth/spreadsheets')
  .setPropertyStore(PropertiesService.getScriptProperties())
  .setCache(CacheService.getUserCache())
  .setParam('access_type', 'offline')
  .setParam('approval_prompt', 'force');
  return service;
}

function writeData() {
  var service = getSheetsAuthService();
  if (service.hasAccess()) {
    const ssTestID = "ID_DATABASE_SPREADSHEET";
    const ssTestSheet1 = SpreadsheetApp.openById(ssTestID).getSheetByName("Sheet1");
    var values = [
      ['Value1', 'Value2', 'Value3'],
      ['Value4', 'Value5', 'Value6'],
      ['Value7', 'Value8', 'Value9']
    ];
    for (var i = 0; i < values.length; i++) {
      ssTestSheet1.appendRow(values[i]);
    }
  }
}


Ну и соответственно добавил в doGet вызов writeData().

Сделал новую версию развертывания. В результате тестовый пользователь увидел ошибку "Exception: У вас нет разрешения на доступ к этому документу. (строка 17, файл sheets)".

17 строка: const ssTestSheet1 = SpreadsheetApp.openById(ssTestID).getSheetByName("Sheet1");


Почему так происходит и как правильно использовать сервисный аккаунт, чтобы от имени других пользователей записывать данные в таблицу, но при этом не давать им прямого доступа к ней?
  • Вопрос задан
  • 758 просмотров
Решения вопроса 1
oshliaer
@oshliaer Куратор тега Google Apps Script
Google Products Expert
Вы не можете исполнять код Apps Script от сервисного аккаунта напрямую, т.к. у СА нет ручек и он не может нажимать на кнопочки. Максимум, что вы можете, это опубликовать приложение как Server Execution и вызвать его от имени СА.

Но в общем смысле, это похоже на тупиковую ветвь развития приложения в Apps Script. Почему бы вам не создать два приложение, одно для пользователей, а из него уже вызывать ваше приложение, которое все выполняет от вашего имени?

Сервисные аккаунты это не про анонимизацию, а про бездушные машины, которые должны что-то делать за пользователей. У СА очень ограничен ресурс и области видимости.

Но вопрос хороший. Я даже оставлю ему сложность "Средний".
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы