非auth.uid作为用户ID时,Firebase Realtime Database规则实现咨询
适配自定义user_id的Firebase Realtime Database聊天安全规则方案
问题背景
使用Firebase Realtime Database搭建聊天功能,其余数据存储在外部数据库。官方安全规则示例均基于auth.uid与user_id直接匹配的逻辑,但当前场景中自定义user_id与Firebase的auth.uid不一致,无法直接套用官方规则。
现有数据库结构:
{ // Chats contains only meta info about each conversation // stored under the chats's unique ID "chats": { "id1": { "title": "Historical Tech Pioneers", "lastMessage": "ghopper: Relay malfunction found. Cause: moth.", "timestamp": 1459361875666 }, "id2": { ... }, "id3": { ... } }, // Conversation members are easily accessible // and stored by chat conversation ID "members": { "id1": { "ghopper": true, "alovelace": true, "eclarke": true }, "id2": { ... }, "id3": { ... } }, // Messages are separate from data we may want to iterate quickly // but still easily paginated and queried, and organized by chat // conversation ID "messages": { "id1": { "m1": { "senderid": "userid2", "message": "The relay seems to be malfunctioning.", "timestamp": 1459361875337 }, "m2": { ... }, "m3": { ... } }, "id2": { ... }, "id3": { ... } }, "users": { "userid1": { "name": "test", "city": "test", "contacts": { "userid2": true, "userid3": true } }, "userid2": { ... }, "userid3": { ... } } }
核心解决方案
要实现权限验证,关键是建立auth.uid到自定义user_id的映射关系,在规则中通过auth.uid反向查找对应的自定义user_id,再用这个id去验证用户是否具备操作权限。
步骤1:更新users节点结构
在每个自定义user_id的节点下添加auth_uid字段,存储对应用户的Firebase auth.uid,方便规则中反向查询:
"users": { "userid1": { "name": "test", "city": "test", "auth_uid": "firebase-auth-uid-1", // 新增:关联Firebase auth的uid "contacts": { "userid2": true, "userid3": true } }, "userid2": { "auth_uid": "firebase-auth-uid-2", ... }, "userid3": { "auth_uid": "firebase-auth-uid-3", ... } }
步骤2:编写适配后的安全规则
通过查询users节点获取当前认证用户对应的自定义user_id,后续权限验证均基于这个自定义id:
{ "rules": { // 定义变量,获取当前认证用户对应的自定义user_id "vars": { "currentUserId": "root.child('users').orderByChild('auth_uid').equalTo(auth.uid).key()" }, "chats": { "$chatId": { ".read": "auth != null", // 验证当前用户是该聊天的成员 ".write": "auth != null && root.child('members/' + $chatId + '/' + vars.currentUserId).exists()" } }, "members": { "$chatId": { ".read": "auth != null", ".write": "auth != null && root.child('members/' + $chatId + '/' + vars.currentUserId).exists()", "$memberId": { ".write": "auth != null && root.child('members/' + $chatId + '/' + vars.currentUserId).exists() && !root.child('members/' + $chatId + '/' + $memberId).exists()" } } }, "messages": { "$chatId": { ".read": "auth != null", ".write": "auth != null && root.child('members/' + $chatId + '/' + vars.currentUserId).exists()", "$messageId": { // 验证消息发送者是当前用户的自定义user_id ".write": "auth != null && root.child('messages/' + $chatId + '/' + $messageId + '/senderid').val() == vars.currentUserId", ".validate": "newData.hasChildren(['message', 'timestamp'])" } } }, "users": { "$userId": { // 验证当前用户的auth.uid匹配该自定义user_id的auth_uid字段 ".read": "auth != null && root.child('users/' + $userId + '/auth_uid').val() == auth.uid", ".write": "auth != null && root.child('users/' + $userId + '/auth_uid').val() == auth.uid", "contacts": { ".read": "auth != null && root.child('users/' + $userId + '/auth_uid').val() == auth.uid", ".write": "auth != null && root.child('users/' + $userId + '/auth_uid').val() == auth.uid", "$contactId": { ".write": "auth != null && root.child('users/' + $userId + '/auth_uid').val() == auth.uid && !root.child('users/' + $userId + '/contacts/' + $contactId).exists()" } } } } } }
规则说明
vars.currentUserId:通过Firebase查询规则,从users节点反向查找当前auth.uid对应的自定义user_id,作为权限验证的核心标识- 所有读写权限验证均基于这个自定义user_id,替代官方示例中的
auth.uid - users节点的读写权限通过匹配
auth_uid字段,确保只有用户本人能操作自己的节点
内容的提问来源于stack exchange,提问作者Joaquín Varela
相关产品推荐
相关产品推荐

