Firebase-服务器Firestore读取服务器端渲染的最佳实践

时间:2019-01-06 23:06:44

标签: reactjs firebase firebase-authentication google-cloud-firestore serverside-rendering

我有一个使用Firebase Firestore的服务器端渲染的reactjs应用。

我在网站的某个区域中需要从Firestore检索服务器端的内容。

当前,我正在使用Firestore规则,允许任何人从这些特定文档中读取数据

让我担心的是,某些坏人可能会设置脚本来连续读取我的数据库并堆积我的帐单(因为我们是按每次阅读收取费用,允许任何人执行读取似乎是不明智的。)

当前规则

// Allow anonymous users to read feeds
match /landingPageFeeds/{pageId}/feeds/newsFeed {
  allow read: if true;
}

最好的前进方向?

如何允许我的服务器端脚本从Firestore中读取,但不允许其他人读取?

请记住,这是在服务器端运行之前执行的初始操作,然后以预加载状态为客户端充水。此功能/动作也与客户端共享以进行页面间导航。

我考虑了匿名登录-该方法有效,但是,每次页面加载都会生成一个新的匿名用户-Firebase确实限制了新的电子邮件/密码和匿名用户帐户。它似乎不切实际。

1 个答案:

答案 0 :(得分:0)

解决方案

根据Doug的评论,我进一步考虑了admin SDK。我最终在firebase函数中为需要安全的firestore读取且可以缓存的匿名请求创建了单独的API。

目标

  1. 继续拒绝公开读取我的firestore数据库
  2. 允许匿名用户触发需要从Firestore数据库中获取数据的服务器端渲染的reactjs页面的Firestore读取(例如首次访问者,搜索引擎)。
  3. 防止“ 读取垃圾邮件”,第三方可以使用服务器端CDN缓存进行响应,从而使我的数据库遭受数百万次读取,从而增加了我的云计算成本。 (通过循环调用不必要的读取,我曾经意外地提出了巨额账单-我想确保陌生人不会恶意地这样做)

管理SDK和Firebase函数缓存

admin SDK允许我安全地从firestore中读取。我的firestore security rules可以拒绝未经身份验证的用户的访问。

正在处理 GET 请求的

Firebase函数支持server caching the response。这意味着来自相同查询的后续匹配不会重新运行我的所有功能(firebase读取,其他功能调用),而只是立即再次用相同的数据进行响应。

过程

  1. 匿名客户端访问服务器端呈现的reactjs页面
  2. 服务器上的初始负载呈现会触发firebase函数(https触发器)
  3. Firebase函数使用Admin SDK从受保护的Firestore数据库中读取
  4. 函数将响应缓存3小时res.set('Cache-Control', 'public, max-age=600, s-maxage=10800');
  5. 在接下来的3小时内,来自任何地方的任何客户端的后续请求都会从缓存中得到处理-避免不必要的读取或额外的计算/资源使用

注意-缓存不适用于本地-必须部署到Firebase才能测试缓存效果。

示例功能

const functions = require("firebase-functions");
const cors = require('cors')({origin: true});
const { sendResponse } = require("./includes/sendResponse");
const { getFirestoreDataWithAdminSDK } = require("./includes/getFirestoreDataWithAdminSDK");


const cachedApi = functions.https.onRequest((req, res) => {
    cors(req, res, async () => {
        // Set a cache for the response to limit the impact of identical request on expensive resources
        res.set('Cache-Control', 'public, max-age=600, s-maxage=10800');

        // If POST - response with bad request code - POST requests are not cached
        if(req.method === "POST") {
            return sendResponse(res, 400);
        } else {

            // Get GET request action from query
            let action = (req.query.action) ? req.query.action : null;
            console.log("Action: ", action);

            try {
                // Handle Actions Appropriately
                switch(true) {

                    // Get Feed Data
                    case(action === "feed"): {
                        console.log("Getting feed...");

                        // Get feed id
                        let feedId = (req.query.feedId) ? req.query.feedId : null;

                        // Get feed data
                        let feedData = await getFirestoreDataWithAdminSDK(feedId);

                        return sendResponse(res, 200, feedData);
                    }

                    // No valid action specified
                    default: {
                        return sendResponse(res, 400);
                    }
                }
            } catch(err) {
                console.log("Cached API Error: ", err);
                return sendResponse(res, 500);
            }
        }
    });
});

module.exports = {
    cachedApi
}