我正在使用Firebase开发一个在内部使用云功能作为REST API的应用。我的问题是,是否有一种简单的方法来实现与slack uses类似的每IP /每用户速率限制,除了每IP 和 每个用户基础,而不是每个应用程序(因为它是所有应用程序)。也可以选择支持小型爆发。
示例代码(请参阅// TODO:
条评论):
exports.myCoolFunction = functions.https.onRequest((req, res) => {
// TODO: implement IP rate-limiting here
unpackToken(req).then((token) => { // unpackToken resolves with a response similar to verifyIdToken based on the "Authorization" header contents
// TODO: implement user-based rate-limiting here (based on token.uid)
if (!req.body) return res.status(400).end();
if (typeof req.body.name !== "string") return res.status(400).end();
if (typeof req.body.user !== "string") return res.status(400).end();
// more input sanitization and function logic here
return res.status(501).end(); // fallback in all requests, do not remove
}).catch(() => res.status(403).end());
});
如果超过速率限制,我想简单地使用529 Too Many Requests
状态代码终止请求。这是为了防止应用程序错误泛滥网络并防止滥用REST API。
这应考虑到Firebase启动/关闭服务器实例并同时运行多个实例。
我也在使用Firestore数据库,如有必要,可以使用旧版实时数据库。
答案 0 :(得分:2)
基于每个用户执行此操作听起来相当简单:
functions-samples
repo。admin.database().ref(`/userCalls/$uid`).push(ServerValue.TIMESTAMP)
。admin.database().ref(`/userCalls/$uid`).orderByKey().startAt(Date.now()-60000)
。我不确定调用方的IP地址是否传递给云功能。如果是,您可以对IP地址执行相同的逻辑。如果它没有通过,那么很难以一种不容易欺骗的方式对其进行限速。
答案 1 :(得分:2)
我制作了一个库,用于限制对Firebase函数的调用: firebase-functions-rate-limiter 该库使用realtimeDB或firestore(可配置)作为后端。它以Frank所描述的类似方法存储数据,但是更经济。它不使用集合,而是使用单个文档,每个限定符均带有数组(例如,用户ID)。这意味着超出的呼叫只有一次读取,而允许的呼叫只有读写。
$ npm i --save firebase-functions-rate-limiter
这里是一个例子:
import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import { FirebaseFunctionsRateLimiter } from "firebase-functions-rate-limiter";
admin.initializeApp(functions.config().firebase);
const database = admin.database();
const limiter = FirebaseFunctionsRateLimiter.withRealtimeDbBackend(
{
name: "rate_limiter_collection",
maxCalls: 2,
periodSeconds: 15,
},
database,
);
exports.testRateLimiter =
functions.https.onRequest(async (req, res) => {
await limiter.rejectOnQuotaExceeded(); // will throw HttpsException with proper warning
res.send("Function called");
});