ac / kalinka
适用于PHP的灵活授权库
Requires
- php: >=5.4.0
This package is not auto-updated.
Last update: 2024-09-14 14:51:46 UTC
README
Kalinka帮助您确定谁可以在您的应用程序中做什么。
此库用于授权,而不是认证。您需要不同的库来实际登录和注销用户、管理密码、OpenID等。Kalinka用于确定用户登录后可以执行哪些操作。
安装
您可以通过composer获取Kalinka
"require": {
...
"ac/kalinka": "dev-master"
}
入门
为您的应用程序创建一个基本的抽象Guard类。Guard是您定义安全策略的地方。策略是返回布尔值的简单方法,其名称以"policy"开头。以下是一个示例
use AC\Kalinka\Guard\BaseGuard; abstract class MyAppBaseGuard extends BaseGuard { protected function policyAdmin($subject) { return $subject->isAdmin(); } }
上面的subject
是要检查权限的用户。这可以是您的应用程序User类的实例(如上面的代码所假设的),也可以是用户名称的简单字符串。重要的是这可以让您了解有关用户的一切,以确定他们可以做什么。
MyAppBaseGuard
是抽象的,因为它没有定义任何操作。操作是表示主题可能想要做的各种事情的字符串,您可能允许或不允许这些操作。对于您更具体的Guard类,您需要提供一个返回数组的getActions
方法。
class DocumentGuard extends MyAppBaseGuard { public function getActions() { return ["read", "write"]; } }
策略也可以接受一个object
作为第二个参数,这是主题试图访问的特定资源。例如,假设您有文档,允许根据用户是否拥有该特定文档以及文档是否“解锁”来访问。
class DocumentGuard extends MyAppBaseGuard { public function getActions() { return ["read", "write"]; } protected function policyDocumentOwner($subject, $object) { return ($object->getOwnerId() == $subject->getId()); } protected function policyDocumentUnlocked($subject, $object) { return !($object->isLocked()); } }
当您的应用程序想要进行实际的访问检查时,这些检查将通过Authorizer完成。Authorizer确定在任何给定情况下应用哪些Guard策略。您可以引用您的Guard中实现的政策,以及简单的默认“允许”策略,该策略始终允许访问。
如果您没有为操作定义任何策略,则默认情况下始终拒绝。
对于大多数基本用例,您可以从SimpleAuthorizer
派生。
use AC\Kalinka\Authorizer\SimpleAuthorizer; use MyApp\Guards\CommentGuard; use MyApp\Guards\DocumentGuard; class MyAppAuthorizer extends SimpleAuthorizer { public function __construct($subject) { parent::__construct($subject); $this->registerGuards([ "document" => new DocumentGuard, "comment" => new CommentGuard, // ... and so on for all your protected resources ]); $this->registerPolicies([ "document" => [ "read" => "allow", "write" => "documentOwner" ], "comment" => [ "read" => "allow", "create" => "allow", "delete" => "admin" ], // ... ]); } }
在所有这些之后,我们就可以进行授权了!每次您想要检查对某些资源的访问是否允许时,只需创建您的Authorizer类的实例并调用can
方法。
use MyApp\MyAppAuthorizer; $auth = new MyAppAuthorizer($currentUser); if ($auth->can("write", "document", $someDocument)) { $someDocument->setContent($newValue); } else { print "Access denied!\n"; }
组合策略
假设您只想在文档解锁且用户拥有它们的情况下允许编辑文档。这可以通过提供策略列表而不是单个字符串来实现。
// ... $this->registerPolicies([ "document" => [ "read" => "allow", "write" => [ "documentUnlocked", "documentOwner" ] ], // ... ]);
有时,如果几个不同的策略中的任何一个允许操作,则允许执行操作,即使其他策略不允许。假设对于编写文档的目的,管理员资格与文档所有者相同,但文档必须解锁的规则适用于所有人。在这种情况下,您可以使用内嵌列表。
// ... $this->registerPolicies([ "document" => [ "read" => "allow", "write" => [ "documentUnlocked", ["documentOwner", "admin"] ] ], // ... ]);
这里的原理是,外层列表是AND连接的,而内层列表是OR连接的。
如果您需要更复杂的策略,您总是可以将其实现为自己的策略。策略可以通过BaseGuard上的checkPolicy
方法相互调用。
角色
SimpleAuthorizer
只适用于非常直接的配置,其中相同的策略适用于所有人。在实际系统中,更常见的情况是人们可以属于多个不同的角色,每个角色都有可能在各种不同的情况下访问资源。实现这一点的最简单方法是扩展 RoleAuthorizer
,它提供了一个 registerRolePolicies()
方法,该方法替代了 SimpleAuthorizer
的 registerPolicies()
方法的功能。
use AC\Kalinka\Authorizer\RoleAuthorizer; use MyApp\Guards\CommentGuard; use MyApp\Guards\DocumentGuard; class MyAppAuthorizer extends RoleAuthorizer { public function __construct(MyUserClass $user) { $roleNames = []; foreach ($user->getRoles() as $role) { $roleNames[] = $role->getName(); } parent::__construct($user, $roleNames); $this->registerGuards([ "document" => new DocumentGuard, "comment" => new CommentGuard, // ... and so on for all your protected resources ]); $this->registerRolePolicies([ "guest" => [ "document" => [ "read" => "allow", ], "comment" => [ "read" => "allow", ] // ... ], "customer" => [ "document" => [ "read" => "allow", "write" => [ "documentUnlocked", "documentOwner" ] ], "comment" => [ "read" => "allow", "create" => "allow", ], // ... ], // ... ]); } }
角色以字符串列表的形式提供。当进行权限检查时,会逐个尝试每个角色;如果用户被分配的任何角色允许该操作,则整体允许。
与我们在 MyAppBaseGuard
的 policyAdmin()
方法中添加的角色策略相比,这是一个更灵活的解决方案。
RoleAuthorizer
还提供了一个名为 'superuser' 的特殊角色,它自动允许所有操作。
部分包含的角色
有时您可能会遇到特殊的情况,其中所需的权限与您的角色不完全匹配。例如,您可能有一个拥有“贡献者”角色所有权利的用户,但在处理评论时也可以充当“管理员”。您可以通过使用 RoleAuthorizer
派生方法中的 registerRoleInclusions()
方法来处理这种情况。
use AC\Kalinka\Authorizer\RoleAuthorizer; class MyAppAuthorizer extends RoleAuthorizer { public function __construct(MyUserClass $user) { // ... if ($user->isCommentAdmin()) { $this->registerRoleInclusions([ "comment" => "administrator" ]); } } }
也可以仅包含角色中的特定操作
$this->registerRoleInclusions([ "comment" => ["update" => "administrator", "delete" => "administrator"] ]);
这些包含的部分被视为另一个角色;如果任何包含的策略列表批准,或者如果用户常规角色的任何策略列表批准,则允许访问。