我想为ACL创建一个架构;但是,我在实现它的两种方法之间陷入了困境。
我敢肯定,我不想处理级联权限,因为这会导致后端和站点管理员感到困惑。
我想我也可以只和一个角色一起生活。这样的设置将允许在网站扩展时根据需要添加角色和权限,而不会影响现有角色/规则。
首先,我要规范化数据并使用三个表来表示关系。
ROLES { id, name } RESOURCES { id, name } PERMISSIONS { id, role_id, resource_id }
查询以确定是否允许某处某个用户的查询如下所示:
SELECT id FROM resources WHERE name = ? SELECT * FROM permissions WHERE role_id = ? AND resource_id = ? ($user_role_id, $resource->id)
然后我意识到我将只有大约20个资源,每个资源最多具有5个动作(创建,更新,查看等),可能还有8个角色。这意味着我可以公然无视数据规范化,因为我永远不会有数百条可能的记录。
因此,也许像这样的模式更有意义。
ROLES { id, name } PERMISSIONS { id, role_id, resource_name }
这将允许我在单个查询中查找记录
SELECT * FROM permissions WHERE role_id = ? AND permission = ? ($user_role_id, 'post.update')
那么哪个更正确? ACL是否还有其他架构布局?
以我的经验,真正的问题主要归结为是否将发生任何数量的特定于用户的访问限制。
例如,假设您正在设计社区的架构,并且允许用户切换其个人资料的可见性。
一种选择是坚持使用公共/私有配置文件标志,并坚持进行广泛的先占权限检查:“ users.view”(查看公共用户)与例如“ users.view_all”(查看所有用户,对于主持人) 。
另一个涉及更精细的权限,您可能希望他们能够进行配置,以便他们可以使自己(a)所有人都可以看到,(b)亲手挑选的伙伴可以看到,(c)完全保密,甚至(d ),但由他们手工挑选的bozo除外。在这种情况下,您需要为各个行存储与所有者/访问相关的数据,并且需要对其中的一些内容进行大量抽象,以避免实现密集的,面向图的传递闭包。
无论采用哪种方法,我都发现,角色编辑/分配中增加的复杂性被 分配 给各个数据段的权限所带来的轻松/灵活性所抵消,并且以下各项效果最佳:
然后,可以在两个查询中提取生成的面向图,使用您使用的任何一种语言,在合理的时间内一劳永逸地构建所有内容,并将其缓存到Memcache或类似物中以供后续使用。
从那里开始,获取用户的权限就是检查他拥有哪些角色,并使用权限图对其进行处理以获取最终权限。通过验证用户是否具有指定的角色/权限来检查权限。然后基于该权限检查运行查询/发出错误。
如果需要,您可以扩展对单个节点的检查(例如check_perms($user, 'users.edit', $node),“可以编辑此节点”与check_perms($user, 'users.edit')“可以编辑一个节点”),并且最终用户可以使用非常灵活/易于使用的工具。
check_perms($user, 'users.edit', $node)
check_perms($user, 'users.edit')
如开头的示例所示,请警惕过多地转向行级权限。性能瓶颈在检查单个节点的权限方面要比拉出有效节点列表(即仅用户可以查看或编辑的节点)少。如果您不太(非常)精通查询优化,则建议不要在行本身内的标志和user_id字段之外进行任何操作。