Mysql ACL的数据库模式

Mysql ACL的数据库模式,mysql,acl,Mysql,Acl,我想为ACL创建一个模式;然而,我在实现它的两种方法之间左右为难 我很确定我不想处理层叠权限,因为这会导致后端和站点管理员的很多混乱 我想我也可以让用户一次只扮演一个角色。这样的设置将允许在站点增长时根据需要添加角色和权限,而不会影响现有角色/规则 首先,我要规范化数据,并用三个表来表示关系 ROLES { id, name } RESOURCES { id, name } PERMISSIONS { id, role_id, resource_id } 用于确定是否允许用户在某个位置的查询如

我想为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还有其他架构布局吗?

您可以使用集合来分配角色

CREATE TABLE permission (
  id integer primary key autoincrement
  ,name varchar
  ,perm SET('create', 'edit', 'delete', 'view')
  ,resource_id integer );
这意味着我可以明目张胆地锻炼 如我所说,不考虑数据规范化 永远不会超过一对 一百条可能的记录

您期望的行数不是选择标准形式的标准。 规范化与数据完整性有关。它通常通过减少冗余来提高数据完整性

真正要问的问题不是“我将有多少行?”,而是“数据库总是给我正确的答案有多重要?”对于将用于实现ACL的数据库,我会说“非常重要。”

如果有什么区别的话,行数少表明您不需要关心性能,因此5NF应该是一个容易的选择。在添加任何id号之前,您需要点击5NF

一个查询,用于确定用户是否 被允许的地方看起来像 这:

您将其作为两个查询而不是使用内部联接来编写,这表明您可能处于过度状态。(这是观察,不是批评。)


根据我的经验,真正的问题主要在于是否会出现任何数量的特定于用户的访问限制

例如,假设您正在设计社区的模式,并且您允许用户切换其配置文件的可见性

一种选择是坚持使用公共/私有配置文件标志,并坚持广泛的、先发制人的权限检查:“users.view”(查看公共用户)与“users.view_all”(查看所有用户,针对版主)

另一个涉及到更精细的权限,您可能希望他们能够配置一些东西,这样他们就可以(a)让所有人都可以看到,(b)让他们亲手挑选的伙伴都可以看到,(c)完全保密,或者(d)让所有人都可以看到,除了他们亲手挑选的傻瓜。在这种情况下,您需要为单个行存储与所有者/访问相关的数据,并且需要对其中的一些内容进行大量抽象,以避免实现密集的、面向对象的图的传递闭包

无论采用哪种方法,我都发现角色编辑/分配中增加的复杂性被为单个数据块分配权限所带来的轻松性/灵活性所抵消,并且以下几点效果最好:

  • 用户可以有多个角色
  • 角色和权限合并在同一个表中,并带有一个标志以区分两者(在编辑角色/权限时很有用)
  • 角色可以从同一个表中分配其他角色,角色和PERM可以分配权限(但权限不能分配角色)
  • 然后,可以将生成的面向图形拉入两个查询,使用您使用的任何一种语言在合理的时间内一次性构建,并缓存到Memcache或类似工具中以供后续使用

    从这里开始,获取用户的权限就是检查他拥有哪些角色,并使用权限图处理这些角色以获得最终权限。通过验证用户是否具有指定的角色/权限来检查权限。然后根据该权限检查运行查询/发出错误

    如果需要,您可以扩展对单个节点的检查(即,
    check_perms($user,'users.edit',$node)
    for“can edit this node”与
    check_perms($user,'users.edit')
    for“may edit a node”),并且您将为最终用户提供非常灵活/易于使用的功能


    正如开头的示例所示,要小心过度转向行级权限。与拉取有效节点列表(即,仅用户可以查看或编辑的节点)相比,检查单个节点的权限的性能瓶颈更少。如果您(非常)不熟悉查询优化,我建议您不要使用行本身中的标志和用户id字段以外的任何内容。

    这些规则以前不知道。虽然大多数资源上确实需要基本CRUD规则,但可能存在其他自定义规则,因此无法在项目开始时定义这些规则集。您可以在项目结束后使用
    ALTER TABLE
    扩展这些规则集。问题是,这些规则对于某些模块来说是唯一的。也许“修改”是对文章的许可,“退款”是对支付系统的许可。另外,ALTER TABLE在大型数据集上的速度不是很快,每次需要添加新权限时都很麻烦。@Xeoncross,IIRC,ALTER TABLE在集合末尾添加项时只会导致更新表头(即.frm文件),而不会更新表本身。只要集合中的更改不会导致数据量增加(一个字节最多8个集合项,一个单词最多16个集合项,一个dword最多32个),您就可以在单个查询中使用正确的,
    SELECT id FROM resources WHERE name = ?
    SELECT * FROM permissions 
    WHERE role_id = ? AND resource_id = ? ($user_role_id, $resource->id)
    
    SELECT p.* 
    FROM permissions p
    INNER JOIN resources r ON (r.id = p.resource_id AND 
                               r.name = ?)