firebase - 使用 Cloud Functions/Admin SDK 在 Google Firestore 和 Google Sheets 之间同步数据

标签 firebase google-sheets google-cloud-firestore google-cloud-functions

在使用 Cloud Firestore 作为数据后端时,我需要与非技术站点管理员(编辑、销售团队等)共享一些数据集合。此外,我希望授予这些人编辑存储在 Cloud Firestore 中的数据的权限。

Google 表格是站点管理员非常熟悉的工具,它可以节省我开发 CRUD 管理面板的时间,例如从头开始用于数据更新和查看的界面。

这个堆栈溢出 answer展示了如何使用云功能和深度级别发送数据,这个 Github library可以使用 Google Apps 脚本从 Firestore 获取数据(我希望使用 Cloud Functions 或 Firebase Admin SDK 来完成),但我仍在尝试弄清楚如何制作基于端到端表格的界面。

请指导是否有更好的替代方案来实现相同的目标。从 SQL 数据库和 Django 自动创建的管理界面切换到 Firebase-Firestore NoSQL 世界时,我遇到了一些困难。

最佳答案

我了解到您希望能够从 Google 表格调用 Cloud Functions 以便为 Firestore 构建“基于表格的端到端界面”。

您可以使用 UrlFetchApp发出请求以获取 HTTP Cloud Function 的 URL 的类.

您的 Apps 脚本代码如下:

function callSimpleHTTPCloudFunction() {

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

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

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

}

虽然您的 Cloud Function 会是这样的:

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

这是 Cloud Functions 的一个非常简单的示例,但您可以调整此 Cloud Functions 以从/向 Firestore 读取和写入数据。看看这个官方视频作为起点:https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3


现在,如果您想以这样一种方式对您的用户进行身份验证,您可以控制谁可以通过 Cloud Function 访问您的数据,这会有点复杂。

有一个官方的 Cloud Function 示例展示了“如何将 HTTPS 函数限制为仅供您应用的 Firebase 用户使用”:https://github.com/firebase/functions-samples/tree/master/authorized-https-endpoint

如代码注释中所述:“Firebase ID token 需要在授权 HTTP header 中作为不记名 token 传递,如下所示:Authorization: Bearer <Firebase ID Token>。解码成功后,ID token 内容将添加为 req.user。 ”

因此,您需要在 Apps 脚本代码中为 Firebase 用户生成一个 Firebase ID token 。为此,我们将使用 Firebase Auth REST API .在此示例中,我们将使用在 Google 表格 (Session.getActiveUser().getEmail()) 中经过身份验证的用户的电子邮件作为 Firebase 用户名。

如文档中所述,要调用 Firebase Auth REST API,您需要通过 Firebase 管理控制台中的项目设置页面为您的 Firebase 项目获取 Web API key 。

以下 Apps 脚本函数将完成这项工作:

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;

} 

然后,仍然在 Apps 脚本中,您在调用 Cloud Functions 时使用 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 表格发送到 Cloud Function,然后写入 Firestore。

最后,请注意,您可以实现相同的方法从 Google 表格中调用 Firestore REST API而不是调用 Cloud Functions。

关于firebase - 使用 Cloud Functions/Admin SDK 在 Google Firestore 和 Google Sheets 之间同步数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55274440/

相关文章:

javascript - setBackGroundRGB 不接受字符串

google-sheets - 在QUERY中选择两次之间的差异

javascript - AngularFire/Firestore - 将集合和文档作为服务返回

javascript - Firebase Firestore 获取用户相关数据

javascript - Firestore 上的条件 where 查询

javascript - 如何确定 Firebase 身份验证中的用户是新创建的还是现有用户?

maven - 如何从 angular 2 (angular-cli) 项目制作 WAR 文件?

google-apps-script - Google Sheet/Google Script - 在图片上绘制点

typescript - Firebase 类型和默认 tslint.json 的非隐式依赖

javascript - Dart-从字符串中提取日期(MM/DD/YYYY)