adamnicholson / judge
授权库
Requires (Dev)
- flatbase/flatbase: dev-master
- phpunit/phpunit: ~4.5
This package is auto-updated.
Last update: 2024-09-17 22:57:17 UTC
README
PHP授权包。
入门
角色与身份
"角色"是应用程序用户可以执行的操作。"角色"通常表示为文本字符串,例如"EDIT_ORDERS","VIEW_LOGS"等。
"身份"表示应用程序的用户。与角色一样,它们也以字符串的形式表示。身份可以是某些账户特定的键,例如电子邮件地址或用户ID,也可以是完全不同的事物,如"console"或"API",甚至是"匿名"。
保持账户和身份之间的这种心理分离是关键 - Judge不了解也不关心账户或用户。
要开始使用基于角色的基本授权,不需要进行任何设置。只需实例化Judge
,并通过allow
允许身份访问一个角色
$judge = new Judge(); // Grant access to edit orders $judge->allow('adam@example.com', 'EDIT_ORDERS'); $judge->check('adam@example.com', 'EDIT_ORDERS'); // true // Revoke access to edit orders $judge->deny('adam@example.com', 'EDIT_ORDERS'); $judge->check('adam@example.com', 'EDIT_ORDERS'); // false
简单吗?很好,现在让我们深入一点。
角色上下文
简单的基于角色的权限适合很多用例,但当一个应用程序开始增长时,你很快就会遇到它们的限制。比如说,你有一个"EDIT_ORDERS"的角色,它适用于所有订单,但你需要让一个特定的身份只能编辑一个特定的订单。你该如何做呢?
在Judge中,你可以通过使用角色"上下文"来实现这一点。角色上下文是你可以传递给allow()
,deny()
和check()
的第三个参数,以给你的规则添加更多的具体性。在实践中,上下文通常用于唯一的标识符,如订单ID。
$judge->allow('adam@example.com', 'EDIT_ORDERS', '5'); $judge->check('adam@example.com', 'EDIT_ORDERS', '5'); // true
角色上下文的好处在于它们能够继承规则。如果一个规则没有明确地授予/撤销对特定角色+上下文组合的访问权限,那么Judge将回退到检查该身份是否被授予/撤销对该角色的访问权限,但不带上下文。
$judge = new Judge(); // Grant access to edit all orders $judge->allow('adam@example.com', 'EDIT_ORDERS'); // Override the above, revoking access specifically to order "10" $judge->deny('adam@example.com', 'EDIT_ORDERS', '10'); $judge->check('adam@example.com', 'EDIT_ORDERS'); // true $judge->check('adam@example.com', 'EDIT_ORDERS', '5'); // true $judge->check('adam@example.com', 'EDIT_ORDERS', '10'); // false
角色继承
角色和上下文一起可以解决许多授权需求,但更大的系统可能需要更复杂的继承规则。这就是我们引入角色"父角色"的原因。
配置角色父角色看起来像这样
$judge->getRepository()->addRole('{ROLE}', '{PARENT_ROLE}');
如果你调用check()
,但身份没有被明确授予或撤销对角色的访问权限,但该角色有一个定义的父角色,那么我们将回退到检查是否存在针对父角色的规则
$judge = new Judge(); // Setup the "EDIT_ORDERS" role with the parent "ORDERS" $judge->getRepository()->addRole('EDIT_ORDERS', 'ORDERS'); // Grant access to ORDERS and all child roles $judge->allow('adam@example.com', 'ORDERS'); $judge->check('adam@example', 'EDIT_ORDERS'); // true
你可以根据需要在你角色的父角色层次结构中设置任意多的级别
$judge = new Judge(); $repo = $judge->getRepository(); $repo->addRole('DELETE_ORDERS', 'CHANGE_ORDERS'); $repo->addRole('CHANGE_ORDERS', 'VIEW_ORDERS'); $repo->addRole('VIEW_ORDERS', 'ORDERS'); // Grant access to ORDERS and all children $judge->allow('adam@example.com', 'ORDERS'); $judge->check('adam@example', 'EDIT_ORDERS'); // true // Override the above for access to CHANGE_ORDERS and its children recursively $judge->deny('adam@example.com', 'CHANGE_ORDERS'); $judge->check('adam@example', 'ORDERS'); // true $judge->check('adam@example', 'VIEW_ORDERS'); // true $judge->check('adam@example', 'CHANGE_ORDERS'); // false $judge->check('adam@example', 'DELETE_ORDERS'); // false
身份继承
身份继承的工作方式与角色继承相同
$judge = new Judge(); $repo = $judge->getRepository(); $repo->addIdentity('adam', 'customer_service'); $judge->allow('customer_service', 'EDIT_ORDERS'); $judge->check('adam', 'EDIT_ORDERS'); // true
整合一切
角色上下文、角色父角色和身份父角色都是堆叠的,共同工作以提供真正强大的授权系统。
按照优先级顺序
- 传递的身份-角色-上下文组合的精确匹配
- 具有相同角色和上下文的父身份
- 传递的身份 + 角色不带任何上下文
- 具有相同角色的父身份不带任何上下文
- 具有原始身份的父角色
- 具有父身份的父角色
逻辑流程
数据结构
角色
身份
规则
持久性
到目前为止的所有示例的主要问题是角色和身份没有在请求之间持久化 - 这意味着你需要在每次请求上重新配置Judge以了解你的身份/角色层次结构,并允许/拒绝所有相关的权限。
这些规则/角色/身份可以通过使用Judge\Repository\Repository
在请求之间持久化,这可以作为第一个参数传递给Judge::__construct()
。
Judge附带了一些Judge\Repository\Repository
实现,可以直接使用。
PDORepository
:将数据存储到兼容PDO的数据库中,例如MySQL、SQLite、PostgreSQLFlatbaseRepository
:存储到平面文件数据库ArrayRepository
:在本请求期间将数据存储在数组中
如果您没有向Judge的构造函数传递
Repository
,则默认使用ArrayRepository
。
PDORepository
将数据存储到兼容PDO的数据库中,例如MySQL、SQLite、PostgreSQL
$pdo = new PDO('mysql:host=db;dbname=site', 'root'); $repo = new Judge\Repository\PDORepository($pdo); $judge = new Judge\Judge($repo);
您可能希望与LazyRepositoryWrapper
一起使用PDORepository
,这样您就无需在实际上请求之前实例化PDO连接。
$repo = new Judge\Repository\LazyRepositoryWrapper(function () { $pdo = new PDO('mysql:host=db;dbname=site', 'root'); return new Judge\Repository\PDORepository($pdo); }); $judge = new Judge\Judge($repo);
ArrayRepository
在本过程中将数据存储在内存数组中。
$judge = new Judge\Judge(new ArrayRepository);
FlatbaseRepository
存储到平面文件数据库。
$storage = new Flatbase\Storage\Filesystem('/some/storage/path'); $flatbase = new Flatbase\Flatbase($storage); $repo = new Judge\Repository\FlatbaseRepository($pdo); $judge = new Judge\Judge($repo);