Firebase 使用云函数/Admin SDK在Google Firestore和Google工作表之间同步数据

Firebase 使用云函数/Admin SDK在Google Firestore和Google工作表之间同步数据,firebase,google-sheets,google-cloud-firestore,google-cloud-functions,Firebase,Google Sheets,Google Cloud Firestore,Google Cloud Functions,在使用Cloud Firestore作为数据后端时,我需要与非技术站点经理(编辑、销售团队等)共享一些数据收集。此外,我希望允许这些人编辑存储在CloudFireStore中的数据 GoogleSheets是网站管理员非常熟悉的工具,它可以节省我开发CRUD管理面板的时间,比如从头开始的数据更新和查看界面 这个堆栈溢出显示了如何使用云函数和深度级别发送数据,这个Github可以使用Google Apps脚本从Firestore获取数据(我希望使用云函数或Firebase Admin SDK来实现

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

GoogleSheets是网站管理员非常熟悉的工具,它可以节省我开发CRUD管理面板的时间,比如从头开始的数据更新和查看界面

这个堆栈溢出显示了如何使用云函数和深度级别发送数据,这个Github可以使用Google Apps脚本从Firestore获取数据(我希望使用云函数或Firebase Admin SDK来实现),但我仍在尝试如何制作一个基于端到端的界面


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

我知道您希望能够从Google工作表调用云函数,以便为Firestore构建“基于工作表的端到端接口”

您可以使用该类发出请求,以获取

您的应用程序脚本代码如下所示:

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' });
});
而您的云功能将类似于:

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功能仅限于应用程序的Firebase用户”:

如代码注释中所述:“Firebase ID令牌需要作为承载令牌在授权HTTP头中传递,如下所示:
Authorization:Bearer
。解码成功后,ID令牌内容将添加为
req.user

因此,您需要在应用程序脚本代码中为Firebase用户生成Firebase ID令牌。为此,我们将使用。在本例中,我们将使用在Google工作表中经过身份验证的用户的电子邮件(
Session.getActiveUser().getEmail()
)作为Firebase用户名

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

以下应用程序脚本函数将执行此任务:

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

}
函数调用securedhttpcloudfunction(){
const authHeader={“Authorization”:“Bearer”+getToken()};
常量url=”https://us-central1-.cloudfunctions.net/securedHttp/";
const response=UrlFetchApp.fetch(url{
方法:“get”,
标题:authHeader,
muteHttpExceptions:true,
});
Logger.log(响应);
//在这里,您可以使用云函数的响应执行所需操作,例如填充工作表
}
云功能代码如下,改编自官方示例

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);
const functions=require('firebase-functions');
const admin=require('firebase-admin');
admin.initializeApp();
const cors=require('cors')({
来源:真实
});    
const express=require('express');
const cookieParser=require('cookie-parser')();
常量app=express();
//验证在授权HTTP头中传递的Firebase ID令牌的Express中间件。
//Firebase ID令牌需要作为承载令牌在授权HTTP头中传递,如下所示:
//“授权:持票人”。
//解码成功后,ID令牌内容将添加为“req.user”。
const validateFireBaisedToken=(请求、恢复、下一步)=>{
log('检查请求是否使用Firebase ID令牌授权');
如果(
!req.headers.authorization||
!req.headers.authorization.startsWith('承载人')
) {
控制台错误(
“没有在授权标头中将Firebase ID令牌作为承载令牌传递。”,
'请确保通过提供以下HTTP标头来授权您的请求:',
“授权:持票人”
);
res.status(403).发送(“未授权”);
回来
}
让idToken;
如果(
请求授权&&
请求头、授权、启动和(‘承载人’)
) {
log('Found“Authorization”header');
//从授权标头读取ID令牌。
idToken=req.headers.authorization.split('Bearer')[1];
console.log(idToken);
}否则{
//没有饼干
res.status(403).发送(“未授权”);
回来
}
管理
.auth()
.verifyIdToken(idToken)
。然后(decodedIdToken=>{
log('ID令牌正确解码',decodedIdToken);
req.user=decodedIdToken;
返回next();
})
.catch(错误=>{
console.error('验证Firebase ID令牌时出错:',错误);
res.status(403).发送(“未授权”);
});
};
应用程序使用(cors);
应用程序使用(cookieParser);
应用程序使用(ValidateFireBaisedToken);
应用程序获取(“/”,(请求,请求)=>{
res.send(`您的电子邮件是${req.user.email}`);
});
//此HTTPS端点只能由Firebase用户访问。
//请求需要通过提供“Authorization”HTTP头进行授权
//值为'Bearer`。
exports.securedHttp=functions.https.onRequest(app);

您可以很好地使用POST和有效负载编写类似的函数,以便将数据从Google Sheet发送到云函数,然后写入Firestore


最后,请注意,您可以使用相同的方法从Google工作表中调用,而不是调用云函数。

我知道您希望能够从Google工作表中调用云函数,以便构建“基于工作表的端到端”