如何利用Firebase实时数据库规则按UID限制巡检员读写对应案件
问题:Firebase实时数据库规则实现巡检员按UID匹配案件权限
数据库数据结构
https://dev-xxx-xxxx-xxx-xxx.firebaseio.com/ ↓idCase ↓IdLoans -NREvs1K2xaCcjP37ALm →LoanNumber: "0001" →InspectorName: "John" →PropertyAddress: "F-32 Maa St." →Property Condition: "No Data" →Property Occupancy: "No Data" -NRIs9ibnlVVhI2QtfGt →LoanNumber: "0002" →InspectorName: "'Jane" →PropertyAddress: "D-12 Doo St." →Property Condition: "No Data" →Property Occupancy: "No Data" -NRJEhrCJAY-QoQFn0wX →LoanNumber: "0003" →InspectorName: "'Joah" →PropertyAddress: "Y-20 Saa St." →Property Condition: "No Data" →Property Occupancy: "No Data" -NT-HB1Z3cUDG7jvvx2c →LoanNumber: "0004" →InspectorName: "John" →PropertyAddress: "F-34 Maa St." →Property Condition: "No Data" →Property Occupancy: "No Data"
尝试的无效规则
{ "rules": { "idCase": { "IdLoans": { ".read": "auth != null && (auth.uid === 'z6Iy8yZFZ1Mf6ZsbfgnF1GlFYtN2' && query.orderByChild === 'InspectorName' && query.equalTo === 'John' || auth.uid === 'tMfqfdh6B8hRBrZKT0fjRblUyO13' && query.orderByChild === 'InspectorName' && query.equalTo === 'Joah' || auth.uid === 'ynn3RTNQ7CQ6ENIRaXy55AvvFb73' && query.orderByChild === 'InspectorName' && query.equalTo === 'Jane')", ".write": "auth != null && (auth.uid === 'z6Iy8yZFZ1Mf6ZsbfgnF1GlFYtN2' && query.orderByChild === 'InspectorName' && query.equalTo === 'John' || auth.uid === 'tMfqfdh6B8hRBrZKT0fjRblUyO13' && query.orderByChild === 'InspectorName' && query.equalTo === 'Joah' || auth.uid === 'ynn3RTNQ7CQ6ENIRaXy55AvvFb73' && query.orderByChild === 'InspectorName' && query.equalTo === 'Jane')" } } } }
解决方案
原规则问题分析
- 硬编码UID与巡检员姓名的对应关系,新增或修改用户必须更新规则,扩展性差
- 写规则错误依赖
query条件,写操作无需查询参数,应直接验证新数据的InspectorName - 数据中
Jane和Joah字段值带多余单引号('Jane'、'Joah'),与规则中的字符串不匹配,导致权限验证失败
方案1:使用用户自定义Claims(推荐)
通过Firebase Auth自定义Claims关联用户UID和巡检员姓名,无需硬编码规则:
- 为每个用户设置自定义Claims(使用Firebase CLI):
firebase auth:set-custom-claims z6Iy8yZFZ1Mf6ZsbfgnF1GlFYtN2 '{"inspectorName": "John"}' firebase auth:set-custom-claims tMfqfdh6B8hRBrZKT0fjRblUyO13 '{"inspectorName": "Joah"}' firebase auth:set-custom-claims ynn3RTNQ7CQ6ENIRaXy55AvvFb73 '{"inspectorName": "Jane"}'
注意:数据中
'Jane'和'Joah'的单引号需删除,保持与Claims中字符串一致
- 编写数据库规则:
{ "rules": { "idCase": { "IdLoans": { // 读权限:用户需登录,且查询必须按InspectorName筛选并匹配自身Claims中的姓名 ".read": "auth != null && query.orderByChild === 'InspectorName' && query.equalTo === auth.token.inspectorName", // 写权限:用户需登录,且新数据的InspectorName必须匹配自身Claims中的姓名 ".write": "auth != null && newData.child('InspectorName').val() === auth.token.inspectorName" } } } }
方案2:使用用户映射节点(适合无法使用Claims的场景)
在数据库中新增节点存储UID与巡检员姓名的映射,规则通过该节点验证权限:
- 添加
userInspectorMap节点:
{ "userInspectorMap": { "z6Iy8yZFZ1Mf6ZsbfgnF1GlFYtN2": "John", "tMfqfdh6B8hRBrZKT0fjRblUyO13": "Joah", "ynn3RTNQ7CQ6ENIRaXy55AvvFb73": "Jane" } }
- 编写数据库规则:
{ "rules": { // 禁止普通用户访问映射节点,仅管理员可修改 "userInspectorMap": { ".read": false, ".write": false }, "idCase": { "IdLoans": { ".read": "auth != null && query.orderByChild === 'InspectorName' && query.equalTo === root.child('userInspectorMap').child(auth.uid).val()", ".write": "auth != null && newData.child('InspectorName').val() === root.child('userInspectorMap').child(auth.uid).val()" } } } }
内容的提问来源于stack exchange,提问作者Samuel Garcia Agosto
相关产品推荐
相关产品推荐

