Cloud Functions写入Firestore时能否使用Firestore Rules校验权限
结论
这个需求完全可以实现,无需在云函数代码中重复编写用户权限校验逻辑。
核心原理
默认使用服务账号无参初始化的Firebase Admin SDK拥有项目全量资源读写权限,会直接绕过Firestore Security Rules校验。只要调整云函数内Firestore实例的初始化身份,使用发起请求的终端用户身份凭据初始化受限实例,该实例的所有读写操作就会和客户端直连Firestore的行为完全一致,自动触发已配置的Security Rules完成权限校验,不符合规则的操作会直接返回权限拒绝错误。
实现步骤
- 客户端侧:用户登录后,调用Firebase Auth提供的
getIdToken()方法获取当前用户的有效ID令牌,调用云函数时将该令牌放在请求参数或请求头中传递给云函数。 - 云函数侧:
- 保留默认的Admin SDK初始化逻辑,用于校验客户端传递的ID令牌合法性,绝对不要直接信任客户端传入的用户ID,必须先完成令牌校验。
- 校验通过后,使用拿到的用户身份信息生成带身份上下文的凭据,初始化受限的Firestore实例,参考代码如下:
const admin = require('firebase-admin'); // 默认初始化的实例拥有全量权限,仅用于校验ID Token admin.initializeApp(); /** * 生成受Security Rules约束的Firestore实例 * @param {string} clientIdToken 客户端传递的用户ID Token * @returns 受规则约束的Firestore实例 */ async function getRulesConstrainedFirestore(clientIdToken) { // 校验ID Token合法性,解析用户身份 const decodedUserToken = await admin.auth().verifyIdToken(clientIdToken); const appIdentifier = `user-context-app-${decodedUserToken.uid}`; // 避免同个函数实例内重复初始化app if (admin.apps.some(app => app.name === appIdentifier)) { return admin.app(appIdentifier).firestore(); } // 以对应用户身份初始化App,该App下的Firestore操作自动匹配Security Rules const userContextApp = admin.initializeApp({ credential: admin.credential.applicationDefault(), databaseAuthVariableOverride: { uid: decodedUserToken.uid, token: decodedUserToken } }, appIdentifier); return userContextApp.firestore(); }- 后续所有代表用户执行的Firestore写入操作,都使用上述方法返回的Firestore实例完成即可,权限校验逻辑会完全复用你已经配置好的Firestore Rules,无需额外编码。
注意事项
- 只有存在明确终端用户上下文的云函数(比如HTTP触发、可调用类型云函数)适合使用该方案,Firestore触发器、定时任务等无对应操作用户的服务端内部场景,无法套用面向用户的Security Rules。
- 默认初始化的全量Admin实例不要直接用于用户发起的写操作,否则依然会绕过规则校验。
- 初始化带用户上下文的App时要传入唯一的实例名称(比如示例中拼接uid的命名方式),避免函数实例复用时出现重复初始化的报错。
内容的提问来源于stack exchange,提问作者Maximilian Dietel
相关产品推荐
相关产品推荐

