Firebase 规则 : how to restrict access based on user role

标签 firebase firebase-realtime-database firebase-security

我是 Firebase 新手,正在尝试了解安全规则。为此,我正在实现项目 - 团队成员 - 任务的典型功能。 每个项目都会有一个团队负责人、多个成员和多个任务。

这是我试图实现的结构和规则(也称为要求):

/Members - each member has { displayName, email, emailVerified }
    any logged in user should be able to read data from Members (to get the 
        display names of all users)
    any logged in user should be able to update his/her record

/Projects - each project has { Lead, Members{}, Name, Tasks{} }
    any logged in user should be able to read the list of projects
    any logged in user should be able to read the list of members (if possible
        only for the projects where they are part of)
    any logged in user should be able to read the list of tasks (if possible only 
        for the projects where they are part of)
    only the team leader should be able to update project details i.e.
        - add / remove members
        - add / remove tasks
        - change project title

/Tasks - { project, status, title }
    team leader / team members should be able to read the tasks
    team leader can add/edit/delete tasks
    team members can update only status (of a task that is associated with their project)
    team leader / team members should be able to filter project tasks based on 
    task status (completed / not completed)

我设置了以下 Firebase 规则:

{
 "rules": {
    "Members": {
        ".read": "auth != null",
        "$mid" : {
            ".write": "auth != null && auth.uid == $mid"
        }
    }, // Members
    "Projects": {
        ".read": "auth != null",
        // only team lead can edit project details
        ".write": "auth != null && auth.uid == data.child('Lead').val()",
        // Lead and Name are mandatory fields
        ".validate": "newData.hasChildren(['Lead', 'Name'])",
        "Name": {
            ".validate": "newData.isString() && newData.val().length > 0"
        },
        "Lead": {
            ".validate": "root.child('Members/' + newData.val()).exists()"
        },
        "Members": {
            "$mid": {
                ".validate": "root.child('Members/' + $mid).exists()"
            }
        },
        "Tasks": {
            "$tid": {
                ".validate": "root.child('Tasks/' + $tid).exists()"
            }
        }
    }, // Projects
    "Tasks": {
        // allow read / write only if current user is team lead or a member of the project
        ".read": "(auth != null) && (data.child('project').val() == 'Project1')",
        ".write": "auth != null && ( root.child('Projects/' + newData.child('project').val() + '/Lead').val() == auth.uid || root.child('Projects/' + newData.child('project').val() + '/Members/' + auth.uid).exists() )",
        ".validate": "newData.hasChildren(['project', 'status', 'title'])",
        "status": {
            ".validate": "newData.isString() && newData.val().length > 0"
        },
        // if team member is saving the item, allow changes only to status
        "title": {
            ".validate": "(root.child('Projects/' + newData.parent().child('project').val() + '/Lead').val() == auth.uid) ? newData.isString() && newData.val().length > 0 : data.exists() && data.val() == newData.val()"
        }
    } // Tasks
 } // rules
}

目前我正在评估 .read 功能。我尚未测试 .write 功能。

我能够获取给定项目的Members列表(成员的displayName)。 但是,在获取项目的任务详细信息(来自 /Tasks)时,我收到权限被拒绝错误。

请注意,我想对 Tasks 使用与 .write 规则相同的 .read 规则。但当我收到错误时,我将其更改为当前规则(这样,任何经过身份验证的用户都可以读取 Project1 的任务 - Project1 是项目的关键) 。即使那样我的许可也被拒绝。如果我只保留 "auth != null" 那么我就能够读取任务,但这不是我想要的。

有人可以帮助我了解我应该对 Firebase 规则进行哪些更改才能实现上述要求吗?

最佳答案

尝试不同的组合后,我发现了以下结果。

我试图访问/TasksorderByChild('project').equalTo(projectKey)以便获取与项目相关的任务的详细信息。但是当我这样做时,.read规则在 /Tasks 处执行级别并且没有名为 'project' 的 child 在那个级别。 'project'可以通过 /Tasks/<taskId>/project 获取。所以我需要更改 Task规则为:

"Tasks": {
    "$tid": {
        // allow read / write only if current user is team lead or a member of the project
        ".read": "auth != null && ( root.child('Projects/' + data.child('project').val() + '/Lead').val() == auth.uid || root.child('Projects/' + data.child('project').val() + '/Members/' + auth.uid).exists() )",
        ".write": "auth != null && ( root.child('Projects/' + newData.child('project').val() + '/Lead').val() == auth.uid || root.child('Projects/' + newData.child('project').val() + '/Members/' + auth.uid).exists() )",
        ".validate": "newData.hasChildren(['project', 'status', 'title'])",
        "status": {
            ".validate": "newData.isString() && newData.val().length > 0"
        },
        // if team member is saving the item, allow changes only to status
        "title": {
            ".validate": "(root.child('Projects/' + newData.parent().child('project').val() + '/Lead').val() == auth.uid) ? newData.isString() && newData.val().length > 0 : data.exists() && data.val() == newData.val()"
        }
    }
} // Tasks

即使此规则访问 /TasksorderByChild('project').equalTo(projectKey)给予许可被拒绝。这是因为现在没有.read规则定义于/Tasks等级。所以我需要改变程序逻辑来迭代/Projects/<projectId>/Tasks对于每个 taskId访问 /Tasks/<taskId> 。当我这样做时,.read规则得到正确评估,用户只能访问其所属项目的任务详细信息。然后我需要在客户端处理这些任务详细信息,以区分已完成的任务和未完成的任务。

我尚未验证 .write.validate规则。但与此同时,我会等待有人确认我的理解或纠正它。

关于Firebase 规则 : how to restrict access based on user role,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38725549/

相关文章:

android - 如何检查电话号码是否已存在于 Firebase 身份验证中?

android - 基于播放服务测量的多个版本请求

firebase - 对象数据类型的 Firestore 规则

javascript - Firebase Web 应用程序的管理员 View : How To

javascript - Angular 和 Firebase : Cannot find namespace 'firebase'

firebase - 检查 Firestore 上是否存在文档,无需 get() 完整文档数据

firebase - 按整数对文档进行排序Firestore Kotlin

android - 将具有动态值的 Firebase 数据库转换为 Kotlin 数据类的最佳实践

javascript - 在 Firebase 中,如何更新上一级所有节点的子节点?

firebase - 在 Firestore 安全规则 "List"操作中使用变量