firebase规则:如何根据用户角色限制访问

时间:2016-08-02 16:07:58

标签: firebase firebase-realtime-database firebase-security

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

以下是我试图实施的结构和规则(a.k.a.要求):

/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)时,我获得了权限被拒绝错误。

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

有人可以帮助我了解我应该对Firebase规则做出哪些更改,以便实现上面给出的要求吗?

1 个答案:

答案 0 :(得分:2)

在尝试了不同的组合后,我发现了这一点。

我尝试使用/Tasks访问orderByChild('project').equalTo(projectKey),以获取与项目相关的任务的详细信息。但是当我执行此操作时,.read规则将在/Tasks级别执行,并且该级别没有名为'project'的子级。 '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

即使使用此规则,/Tasks访问orderByChild('project').equalTo(projectKey)也会被拒绝。这是因为现在.read级别没有定义/Tasks规则。所以我需要更改程序逻辑以迭代/Projects/<projectId>/Tasks和每个taskId访问/Tasks/<taskId>。执行此操作时,.read规则得到正确评估,用户只能访问它们所属的项目的任务详细信息。然后我需要在客户端处理这些任务细节,以分离已完成和未完成的任务。

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