srigi / ipub-security
Nette 框架的 ACL 权限设置器与检查器
Requires
- php: >=5.4
- latte/latte: ~2.2
- nette/application: ~2.2
- nette/bootstrap: ~2.2
- nette/di: ~2.2
- nette/security: ~2.2
- nette/utils: ~2.2
Requires (Dev)
- nette/tester: ~1.6
- tracy/tracy: ~2.2
README
Nette 框架的 ACL 权限设置器与检查器。
srigi/ipub-security
是一个库,允许轻松配置 Nette 框架的 ACL 系统。它支持角色与资源的继承,并且也支持权限断言。
安装
安装 srigi/ipub-security
的最佳方式是使用 Composer。要获取库的最新版本,请在项目的根目录运行以下命令
$ composer require srigi/ipub-security
或者您可以手动指定依赖项
{ "require": { "srigi/ipub-security": "^1.3.0" } }
设置
安装后,您需要注册 DI 扩展。如果您使用的是 Nette 2.3,您可以通过配置来完成此操作
extensions: permission: IPub\Security\DI\SecurityExtension
对于 Nette 2.2,请在您的 bootstrap.php
中注册扩展
$configurator = new Nette\Configurator; // ...some other code IPub\Security\DI\SecurityExtension::register($configurator);
ACL 系统基础教程
Nette ACL 系统带来了一些术语,您在继续之前应该了解。首先,有 资源,一个(角色)想要访问的(权限)。这形成了一个 权限。示例是最好的老师
资源 - intranet
,salesModule
,serversDashboard
,databaseServersDashboard
角色 - admininstrator
,guest
,authenticated
,employee
,sales
,engineer
权限 - access
,powerOn
,powerOff
,reboot
权限 - 这只是当您组合上述三个实体时的抽象概念
authenticated
可以access
intranet
engineer
可以reboot
serversDashboard
administrator
可以在ALL
上做ALL
资源 和 角色 可以相互继承并创建层次结构
intranet
├ salesModule
└ serversDashboard
└ databaseServersDashboard
administrator
guest
└ authenticated
└ employee
├ sales
└ engineer
└ backend-engineer
如果已注册权限(资源
、角色
和 权限
的组合),则会继承下来。在我们的示例中,engineer
可以 access
intranet
,因为它从 authenticated
继承了此权限。
更多关于此的信息可以在 Nette 框架文档的 访问控制 章节中找到。
创建权限
权限由 IPub\Security\Entities\IPermission
的实例表示。此类实例提供了一个 IPub\Security\Entities\IResource
资源实例,一个权限(定义为字符串)和一个断言(定义为可调用对象)。权限的所有三个组件都是可选的。
权限定义必须由实现 IPub\Security\Providers\IPermissionsProvider
的服务提供。库 srigi/ipub-security 有一个此类提供者的示例实现,您可以在项目中使用。或者您可以编写自己的。
使用我们的 PermissionsProvider
定义一组权限非常简单
class MyPermissionsProvider extends IPub\Security\Providers\PermissionsProvider { public function __construct() { $intranet = $this->addResource('intranet'); $this->addPermission($intranet, Nette\Security\IAuthorizator::ALL); $this->addPermission($intranet, 'access'); $this->addPermission($intranet, 'update'); $salesModule = $this->addResource('salesModule', $this->getResource('intranet')); $this->addPermission($salesModule, 'access'); $this->addPermission($salesModule, 'edit', function($acl, $role, $resource, $privilege) { // ...code of permission assertion }); // ... more permissions definitions } }
现在只需注册您的权限提供者
services: - MyPermissionsProvider
创建角色与分配权限
同样,权限也有其自己的接口,并且需要一个提供者服务。此提供者还应将权限分配给角色
class MyRolesProvider extends IPub\Security\Providers\RolesProvider { /** * @param MyPermissionsProvider $permissionsProvider */ public function __construct(MyPermissionsProvider $permissionsProvider) { $permissions = $permissionsProvider->getPermissions(); $this->addRole(Entities\IRole::ROLE_ADMINISTRATOR); $this->addRole(Entities\IRole::ROLE_ANONYMOUS); $this->addRole(Entities\IRole::ROLE_AUTHENTICATED, $this->getRole(Entities\IRole::ROLE_ANONYMOUS), $permissions['intranet:access']); $this->addRole('employee', $this->getRole(Entities\IRole::ROLE_AUTHENTICATED)); $this->addRole('sales', $this->getRole('employee'), [ $permissions['salesModule:'], ]); $this->addRole('engineer', $this->getRole('employee'), [ $permissions['servers:access'], ]); // ...more roles & permissions assignments }
别忘了注册您的角色提供者
services: - MyRolesProvider
现在您已设置好了!
检查权限
库提供了一个PHP特性,这使得我们可以愉快地查询我们刚刚配置好的Nette ACL系统。请注意,特性从PHP 5.4开始可用,对于较旧版本的PHP,您必须复制/粘贴特性的内容。此特性仅在presenter中有效。
class BasePresenter extends Nette\Application\UI\Presenter { use IPub\Security\TPermission; }
使用注解
您可以通过这组注解来微调检查逻辑
/** * @Secured * @Secured\User(loggedIn) * @Secured\Resource(RESOURCE_NAME) * @Secured\Privilege(PRIVILEGE_NAME) * @Secured\Permission(RESOURCE_NAME: PRIVILEGE_NAME) * @Secured\Role(ROLE_NAME) */ class IntranetPresenter extends BasePresenter { /** * @Secured * @Secured\Permission(RESOURCE_NAME: PRIVILEGE_NAME) */ public function renderDefault() { } }
@Secured
此注解指示安全系统,presenter将受到权限检查的影响。如果没有它,将完全跳过权限检查!
@Secured\User
此注解接受值loggedIn
或guest
。对任何资源
和任何权限
的访问仅由当前用户的登录状态控制。
以下注解在登录过程中分配给Nette\Security\User
的角色上工作。
@Secured\Resource
只有当角色被允许访问指定的资源
时,才授予访问权限。
@Secured\Privilege
只有当角色被允许访问指定的权限
时,才授予访问权限。
@Secured\Permission
上述两种的组合——只有当角色拥有资源: 权限
权限时,才授予访问权限。
@Secured\Role
仅授予指定角色
的访问权限。
在所有适用于*_NAME
的地方,您可以使用逗号分隔的多个名称。
在presenter、组件、模型等中使用
权限检查也可以手动执行。您只需要一个Nette\Security\User
实例,并在其上调用
$user->isAllowed('resource', 'privilege');
分别返回TRUE
或FALSE
。
在Latte中使用
在latte中,您可以使用两个特殊的宏。
<p>This text is for everyone...</p> {ifAllowed resource => 'intranet', privilege => 'access'} <p>But this one is only for special persons...</p> {/ifAllowed}
宏ifAllowed
与注解定义非常相似。您可以使用这里的一个或所有可用参数:用户、资源、权限、权限或角色。
此宏也可以用作n:宏
<p>This text is for everyone...</p> <p n:ifAllowed resource => 'intranet', privilege => 'access'> But this one is only for special persons...</p>
第二个特殊宏用于链接
<a n:allowedHref="Intranet:">Link to Intranet...</a>
宏n:allowedHref
期望一个有效的链接,如果用户没有访问该资源的权限,则不会显示链接。
重定向到登录页面
如果用户未登录且尝试访问受保护的资源,默认操作会抛出Nette\Application\ForbiddenRequestException
异常。然而,如果您配置了所谓的redirectUrl
,当出现这种情况时,请求将被重定向到该URL(登录页面)。
同时,还将存储原始请求的所有参数。这样,您就可以恢复原始请求,并在成功登录后重定向到受保护的资源。要配置redirectUrl
,请将以下内容添加到您的配置中
permission:
redirectUrl: 'Login:default'
要恢复原始请求,在presenter中准备持久的参数backlink
并在登录程序(回调)中使用它
class LoginPresenter { /** @persistent */ public $backlink; public function processLoginForm($form) { // try $this->getUser()->login($form->getValues()); $this->restoreRequest($this->backlink); $this->redirect('Admin:default'); // catch } }
待办事项
- 检查
IPub\Security\Entities\Permission
构造函数的类型 - 将文档示例与测试保持同步
- 对
IPub\Security\Providers\*
进行测试 - latte宏测试
- 检查注解测试逻辑
- 权限断言测试/文档
RolesProvider::allow
、RolesProvider::deny
方法
历史
- 1.3.4 添加
redirectUrl
功能 - 1.3.0 将
RolesModel
和IPub\Security\Models
重命名为RolesProvider
和IPub\Security\Providers
- 1.2.0 重写
Security\Permission
以支持资源继承和权限断言 - 1.1.0 将库克隆到
srigi/ipub-permissions
- 1.0.1 添加角色继承
许可协议
新BSD许可协议或GNU通用公共许可证(GPL)版本2或3,请参阅license.md。