PHP复杂的基于角色的访问控制列表

4
我已经制作好了实现定制化ACL系统所需的数据库和php代码。现在我需要“授权”当前用户,这就是我需要你的建议的地方。
该系统基于灵活的权限分配,既可以分配给系统用户,也可以分配给系统模块。它还具有一些预定义的用户组,例如用户可以完全自定义组。全局规则也可以应用于ACL之上,但其优先级最低,低于分配权限的组或用户。
为了更好地说明:
预定义组:
1.受限制(无访问权限) 2.基本用户 3.高级用户 4.管理员 5.访客(自定义组的示例)
以下是访问级别(名称/值对):
1.拒绝/0 2.允许/1 3.否决/2 4.如果所有者允许/3
注意:“允许”优先于“拒绝”,因此如果您在某个访问中将用户X“禁止”在A组中,但在B组中“允许”,那么他最终会被“允许”。另一方面,如果用户X通过成为“管理员”组的成员获得“完全访问权限”,但是如果他仅在某个访问上被“拒绝”,那么他最终没有访问权限,这意味着“否决”优先于“允许”。
在顶层,您可以拥有以下内容:
1. “管理员”*“1”,这意味着管理员对系统具有完全访问权限 2. “访客”*“0”,这意味着访客不被允许使用任何功能
我的问题是如何处理这些检查?想象一下我们有一个简单的授权机制。我们将在$_SESSION ['user']中拥有一些索引,例如$_SESSION ['user'] ['login'] = true;和$_SESSION ['user'] ['id'] = $ row ['user_id'],对吗?
现在,如果您想要在脚本中实现此机制,您会如何做?
首先我可能会检查全局访问规则。然后我会查看用户是否已经登录。如果是,则只需获取他的所有组,然后查看权限表以查看哪些权限分配给了他的组和用户ID,然后将它们存储在用户会话中。然后,当模块说这是我需要运行的权限时,我会查看用户是否具有请求模块所需的足够访问权限。
看起来相当复杂!非常感谢您提供任何帮助或建议! :)
编辑:
我没有使用任何框架。实际上,我使用了自己的框架。因此,这里没有预先制作的ACL!
更新:
您有关于优先(覆盖/替换?)ACL的有效方法吗?

Deny最高,其次是AllowDisallow。此外,用户分配的ACL优先级最高,然后是组ACL,最后是全局ACL。

最终我得出了以下结论:

这里有一个像这样的Array

$_SESSION['ACL'][$module][$action] = $access_level; // 0, 1, 2, 3

首先,我会查找所有全局规则*,并将它们放入数组中:

// The current user can see the map, applied by a global rule
$_SESSION['ACL']['map']['render'] = 1;

// All the other permissions are disallowed by default
$_SESSION['ACL']['*']['*'] = 0;

// He can edit his preferences, (Owner)
$_SESSION['ACL']['user']['*'] = 3;  

接下来,我将寻找基于组的ACL:

// User could access the Analyze module, all the methods 
// with Permission Name "report". Applied by being a member 
// of "Moderator" Group
$_SESSION['ACL']['analyze']['report'] = 1;

// User NOT allowed to access "groups" module, let say
// it reserved for "admin" group! - To see the ACLs' Overwriting!
$_SESSION['ACL']['groups']['*'] = 0;

毕竟,我正在寻找用户分配的ACL:
// User have Full Access to the "groups" module.
// It's gonna replace the last ACL, applied by "Moderator" group
// Note that the order of processing ACLs is IMPORTANT!
$_SESSION['ACL']['groups']['*'] = 1;

我认为它将完美地工作,有什么想法吗?

现在它运行得非常好 :)


你是在MVC环境下进行这个操作吗? - Pitchinnate
不,我讨厌额外的开销!我有自己的框架。我知道框架通常有自己的ACL! :) - Mahdi
你的自定义框架是否按照MVC结构组织?我不在乎它是否是自定义的。我提供的解决方案仅适用于你的框架按照MVC结构组织的情况。 - Pitchinnate
不,它并不是严格的MVC,但它有一些相似之处。你可以分享你的想法!我相信那会很有帮助的! :) - Mahdi
拒绝(DENY)和不允许(DISALLOW)的区别是什么? - Pitchinnate
显示剩余2条评论
2个回答

2

在MVC环境中,我处理它的方式是创建一个具有以下结构的表:

(id, group_id(int), user_id(int), controller(varchar), action(varchar)) 

然后我使用-1表示通配符,用于group和user_id,使用*表示controller和action。因此,在您的示例中,管理员可以执行任何操作(1,4,-1,,)。或者说,Power User可以修改用户(2,3,-1,user,*)。或者,如果您想要给单个人(user_id为34)一个权限,而不管他们在哪个组中(3,-1,34,user,update)。如果您想要存储0-3以允许、拒绝,请添加一列。然后,您只需检查正在调用哪个控制器和操作,并查找适用于该人员所在的组和他们自己的任何权限。

是的,我明白你的意思!我认为这在MVC结构上会很好用,让我看看我如何以自己的方式实现它...我没有一个确切的MVC结构,但正如我之前所说,它很相似!再次感谢! :) - Mahdi

1

只需创建您的权限/组表:

id, group/permission name

接下来,创建一个多对多的表格,将用户与组链接起来:

id, user_id, group_id

如果您只是使用组权限,那么您不需要访问级别。

然后,在您的代码中,只需像这样检查用户所在的组:

function checkAccess($pageLevelRequired)
{
  // run query based on current user session id
  // run your query to check if the current user belongs to the group required to view this page.
}

有意义吗?


好的,谢谢,但这很简单!我已经有了这种多对多的风格,但我认为我需要在结构上再多做一些工作,至少在这个特定的情况下。 - Mahdi
1
保持简单。如果你想把事情复杂化,那么可以这样做,但如果你不必要(似乎你不需要),那么这可能不是最明智的决定。如果你需要更多的东西,只需问一下即可。 - user1477388
我喜欢保持一切简单易懂,但在这里我们需要添加更多功能,并仍然尽可能地简单。我不想为了简单而牺牲功能。但再次感谢你的帮助! :) - Mahdi
1
好的,就像我说的那样,如果你需要超出这个简单方法的东西,只需提出来,我们会看看还能添加什么。但是,我总是尽量找到最简单的方法,因为通常这将是性能最佳且未来升级/更改最容易的方式。它也不太可能出错;当它是一个非常简单的算法时。 - user1477388
+1谢谢!你说得对,我同意你的看法。然而,我仍然找不到任何更简单的方法来实现这些功能的集成...我会再次查找,看看能否以你的风格做到这一点 :) - Mahdi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接