3

我认为 PHP 人熟悉函数中的E_ALL和其他各种位掩码常量error_reporting()。它们是数字常数,例如:E_ALL手段32676E_NOTICE手段8。我可以说我想要所有错误,但要显示通知,我通过E_ALL & ~E_NOTICE作为参数传递来做到这一点error_reporting()。但本质上,我告诉它32759哪个是32767 - 8.

这些位掩码从函数的输出集中获取它们的值,f(x) = 2^x并对这些值进行加减运算,我们可以微调要得到的错误。

我正在考虑在我的框架中实现一个更可配置的访问控制。为此,我希望设置用户的位掩码将具有相同的将数值相加的方法,问题是我不知道如何实现这一点,如何检查请求的值和当前值:用户是否有权访问 foobar?.

另一个问题是可扩展性。我可能只有 31 个唯一位(因为2^32达到了太大且无法维护的状态),如果我需要经历(现在还没有真正计划)这个障碍,那么迁移会很困难吗?我对访问控制的另一个想法是建立一个表,将user.id他拥有的访问位的整数值和整数值链接在一起。

总结一下,以下两个选项中哪一个是更好的解决方案?

  • 使用用户表中的一个字段来存储位掩码,然后在需要时从中获取请求的位。
  • 在表中定义一组访问标志,并拥有一个将用户链接到访问权限的关系表,利用关系数据库的强大功能来满足我们的需求。

我正在研究第二种方法,但我不知道哪种方法最好用。

4

2 回答 2

0

位掩码

位掩码的原始问题是它们违反了数据建模的约定(在此处的另一个答案中表达,在此处此处进一步阅读)。一个 4 字节的有符号整数可能只包含31不同的值(用整数表示为2 147 483 648),并且很难用它们进行计算。在讨论这个话题之前,Stack Overflow 上有各种各样的问题,我曾经通过这些问题来了解 bistmasks 的工作原理。

测试还表明使用位掩码很难。理解位运算符需要一种感觉,并且迁移基本上是不可能的。(不可能我的意思是,起初,实施位掩码似乎是一件好事,但毕竟与它可以带来的好处相比,它需要太多的支出。)以一个基本的类似门户的网站.. . 我的意思是没有。以堆栈溢出为例例如,它有多少独特的特权。实际上,我曾尝试进行计数,但在复杂性中迷失了自己,但我们需要的数量非常接近,如果还没有超过 31 个唯一值的上述障碍的话。更改位掩码含义的项目更新很可能导致长期需要重新计算,并且如果遇到数据库错误,则更容易出错。

虽然我没有准确的、精确的时序数据,但使用位掩码感觉比 ACL 慢。比较数据库大小,内存和存储空间更大,我们利用关系数据库和索引功能的机会更少。对于网站上的用户权限,如果我们有其他可能使用的方法,位掩码是不行的。

位掩码可以在多种系统中发挥作用,即MaNGOS (最初是从这里提出这个想法的),其中和其他各种模板表定义了使用位掩码的标志但最重要的是,在这些表中,值不可能永远改变,计算是只读的,与用户任意获得和失去权限的网站相反。item_template

示例代码

define('U_NIL', 0);
define('U_EXEC', 1);
define('U_WRIT', 2);
define('U_READ', 4);

$our_perm = 7;
$req_perm = U_EXEC | U_WRIT | U_READ;
var_dump( ($our_perm & $req_perm) == $req_perm ); # Will be bool(true)

$our_perm = 3;
var_dump( ... The same thing ...); # Will be bool(false)

$our_perm = U_READ;
$req_perm = U_READ | U_WRIT;
var_dumo(...); # Will be bool(false)

$our_perm = U_READ | U_WRIT | U_EXEC;
$req_perm = U_READ;
var_dump(...); # Will be bool(true)

等等。

我将省去你的代码行,因为各种 其他 问题恰当地描述了该方法,在某种程度上我永远无法描述它。位掩码看起来不错,位掩码似乎很奇特,但让它们在生产中安定下来是没有意义的。

访问控制列表

原始问题中描述的另一个选项是利用关系数据库和 SQL 语言在数据库中设置权限。我们需要在数据库中再创建两个表:

CREATE TABLE `perm_relation` (
    `row_id` int(10) NOT NULL AUTO_INCREMENT,
    `user_id` int(10) NOT NULL,
    `perm_id` int(10) NOT NULL,
    PRIMARY KEY (`row_id`),
    UNIQUE `permission` (`user_id`, `perm_id`)
) ENGINE=InnoDB;

CREATE TABLE `permission` (
    `id` int(10) NOT NULL AUTO_INCREMENT,
    `name` varchar(64) NOT NULL,
    PRIMARY KEY (`row_id`)
) ENGINE=InnoDB;

perm_relation.perm_id将是指向的外键permission.idperm_relation.user_id将是我们的关系users.id。在此之后,这只是我们如何组合我们的编程逻辑的问题。

SELECT row_id FROM perm_relation
WHERE perm_id = (SELECT id FROM permission WHERE name = "U_SUPERADMIN")
AND user_id = CURRENT_USER_ID;

使用这种方法,我们可以实现更高的兼容性、更快的执行和更轻松的迁移。添加新权限只需要很短的时间,既可以定义新权限,也可以将一些权限授予任意用户。删除同样简单,只需要一个小的 SQL 查询来优化我们的表以删除孤立的整体(例如:具有权限的用户没有在系统中定义相关权限)。

因为我们将这个系统实现到 PHP 环境中,我们可以假设会有某种管理页面,其中有许多依赖于这个权限列表的特性。列出按他们拥有的权限过滤的用户的示例就是一个示例。在这种情况下,ACL 比位掩码好得多,因为我们可以进一步利用JOIN语句……甚至更多。

结论是位掩码和关系模式有不同的用途。位掩码对于用户权限系统来说太多且非常庞大,而在上面提到的 MaNGOS 示例中,关系表将是一种过度杀伤力。

于 2012-08-08T10:57:37.277 回答
0

您永远不应该在数据库中使用代表多个不同值的大整数。每个字段一个值,这是数据建模(或其他东西)的第一定律。

换句话说,你应该有第二张桌子说;一个用户 ID 字段和访问位。

用户特权:

  • 用户 ID,整数,主要
  • 特权,诠释
于 2012-08-03T16:57:05.100 回答