Синхронизируйте данные между Google Firestore и Google Sheets с помощью облачных функций / Admin SDK - PullRequest
0 голосов
/ 21 марта 2019

При использовании Cloud Firestore в качестве бэкэнда данных мне нужно поделиться некоторыми коллекциями данных с нетехническими менеджерами сайтов (редакторами, отделами продаж и т. Д.). Также я хочу предоставить этим людям доступ для редактирования данных, хранящихся в Cloud Firestore.

Google Sheets - очень знакомый инструмент с менеджерами сайтов, который может сэкономить мне время на разработку панели администратора CRUD, такой как интерфейс с нуля, для обновления и просмотра данных.

Это переполнение стека ответ показывает, как отправлять данные с помощью облачной функции и уровней, и эта библиотека Github может получать данные из Firestore с помощью скрипта Google Apps (я хочу это сделать с использованием облачных функций или Firebase Admin SDK), но я все еще пытаюсь выяснить, как создать сквозной интерфейс на основе листов.

Пожалуйста, укажите, есть ли лучшие альтернативы для достижения той же цели. Я сталкиваюсь с некоторыми трудностями при переключении с баз данных SQL и автоматически созданных интерфейсов администрирования Django на мир Firebase-Firestore NoSQL.

1 Ответ

1 голос
/ 21 марта 2019

Я понимаю, что вы хотите иметь возможность вызывать облачную функцию из Google Sheet для создания "сквозного интерфейса на основе листов" для Firestore.

Вы можете использовать UrlFetchApp Класс для отправки запроса на получение URL-адреса Облачной функции HTTP .

Код сценария приложений You будет выглядеть следующим образом:

function callSimpleHTTPCloudFunction() {

 const url = "https://xxxxxxxx.cloudfunctions.net/simpleHttp";

  response = UrlFetchApp.fetch(url, {
      method: 'get'
    })

  respObj = JSON.parse(response.getContentText());
  Logger.log(respObj);

}

Покаваша облачная функция будет выглядеть следующим образом:

exports.simpleHttp = functions.https.onRequest((req, res) => {
  res.send({ msg: 'simpleHttp' });
});

Это очень простой пример облачной функции, но вы можете адаптировать эту облачную функцию для чтения и записи данных из / в Firestore.Взгляните на это официальное видео для начала: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3


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

Существует официальный пример функции облака, который показывает, «как ограничить функцию HTTPS только пользователями Firebase вашего приложения»: https://github.com/firebase/functions-samples/tree/master/authorized-https-endpoint

Как объяснено в комментариях к коду: «Маркер Firebase ID необходимо передать как токен Носителя в HTTP-заголовке авторизации, например: Authorization: Bearer <Firebase ID Token>. При успешном декодировании содержимое токена ID будет добавлено как req.user»

Таким образом, в коде скрипта Apps вам необходимо сгенерировать токен Firebase ID для пользователя Firebase.Для этого мы будем использовать Firebase Auth REST API .В этом примере мы будем использовать электронную почту пользователя, аутентифицированного в Google Sheet (Session.getActiveUser().getEmail()), в качестве имени пользователя Firebase.

Как объяснено в документе, для вызова Firebase Auth REST API вам необходимо получить ключ веб-API для вашего проекта Firebase через страницу настроек проекта в консоли администратора Firebase.

Следующая функция скрипта приложения выполнит эту работу:

function getToken() { {

  const userName = Session.getActiveUser().getEmail();
  const pwd = 'xyz' //For example get the password via a prompt. 
  //This is NOT the password of the account authenticated with Google Sheet, but the password of the Firebase user. In this example, the emails are the same but they are different accounts. 

  const verifyPasswordUrl = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=[API_KEY]" //Replace with your Web API Key

  const payload = JSON.stringify({"email":userName,"password": pwd,"returnSecureToken": true});

  const verifyPasswordResponse = UrlFetchApp.fetch(verifyPasswordUrl, {
        method: 'post',
        contentType: 'application/json',
        muteHttpExceptions: true,
        payload : payload
 });

 const token = JSON.parse(verifyPasswordResponse.getContentText()).idToken;
 return token;

} 

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

function callSecuredHTTPCloudFunction() {

  const authHeader = {"Authorization": "Bearer " + getToken()};

  const url = "https://us-central1-<yourproject>.cloudfunctions.net/securedHttp/";

  const response = UrlFetchApp.fetch(url, {
      method: 'get',
      headers: authHeader,
      muteHttpExceptions: true,
    });

  Logger.log(response);
  //Here do what you want with the response from the Cloud Function, e.g. populate the Sheet

}

Код функции облака был бы следующим, адаптированный из официального примера.

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

const cors = require('cors')({
  origin: true
});    
const express = require('express');
const cookieParser = require('cookie-parser')();

const app = express();

// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const validateFirebaseIdToken = (req, res, next) => {
  console.log('Check if request is authorized with Firebase ID token');

  if (
    !req.headers.authorization ||
    !req.headers.authorization.startsWith('Bearer ')
  ) {
    console.error(
      'No Firebase ID token was passed as a Bearer token in the Authorization header.',
      'Make sure you authorize your request by providing the following HTTP header:',
      'Authorization: Bearer <Firebase ID Token>'
    );
    res.status(403).send('Unauthorized');
    return;
  }

  let idToken;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith('Bearer ')
  ) {
    console.log('Found "Authorization" header');
    // Read the ID Token from the Authorization header.
    idToken = req.headers.authorization.split('Bearer ')[1];
    console.log(idToken);
  } else {
    // No cookie
    res.status(403).send('Unauthorized');
    return;
  }
  admin
    .auth()
    .verifyIdToken(idToken)
    .then(decodedIdToken => {
      console.log('ID Token correctly decoded', decodedIdToken);
      req.user = decodedIdToken;
      return next();
    })
    .catch(error => {
      console.error('Error while verifying Firebase ID token:', error);
      res.status(403).send('Unauthorized');
    });
};

app.use(cors);
app.use(cookieParser);
app.use(validateFirebaseIdToken);
app.get('/', (req, res) => {
  res.send(`Your email is  ${req.user.email}`);
});

// This HTTPS endpoint can only be accessed by your Firebase Users.
// Requests need to be authorized by providing an `Authorization` HTTP header
// with value `Bearer <Firebase ID Token>`.
exports.securedHttp = functions.https.onRequest(app);

Вы можете очень хорошо написать аналогичную функцию с POST и полезной нагрузкой для отправки данных из Google Sheetв облачную функцию и затем напишите в Firestore.

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

...