srigi / ipub-security

Nette 框架的 ACL 权限设置器与检查器

1.3.7 2016-09-19 12:48 UTC

This package is not auto-updated.

Last update: 2024-09-26 00:14:43 UTC


README

Build Status Latest Stable Version Composer Downloads

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 系统带来了一些术语,您在继续之前应该了解。首先,有 资源,一个(角色)想要访问的(权限)。这形成了一个 权限。示例是最好的老师

资源 - intranetsalesModuleserversDashboarddatabaseServersDashboard

角色 - admininstratorguestauthenticatedemployeesalesengineer

权限 - accesspowerOnpowerOffreboot

权限 - 这只是当您组合上述三个实体时的抽象概念

  • 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

此注解接受值loggedInguest。对任何资源和任何权限的访问仅由当前用户的登录状态控制。

以下注解在登录过程中分配给Nette\Security\User的角色上工作。

@Secured\Resource

只有当角色被允许访问指定的资源时,才授予访问权限。

@Secured\Privilege

只有当角色被允许访问指定的权限时,才授予访问权限。

@Secured\Permission

上述两种的组合——只有当角色拥有资源: 权限权限时,才授予访问权限。

@Secured\Role

仅授予指定角色的访问权限。

在所有适用于*_NAME的地方,您可以使用逗号分隔的多个名称。

在presenter、组件、模型等中使用

权限检查也可以手动执行。您只需要一个Nette\Security\User实例,并在其上调用

$user->isAllowed('resource', 'privilege');

分别返回TRUEFALSE

在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::allowRolesProvider::deny方法

历史

  • 1.3.4 添加redirectUrl功能
  • 1.3.0 将RolesModelIPub\Security\Models重命名为RolesProviderIPub\Security\Providers
  • 1.2.0 重写Security\Permission以支持资源继承和权限断言
  • 1.1.0 将库克隆到srigi/ipub-permissions
  • 1.0.1 添加角色继承

许可协议

新BSD许可协议或GNU通用公共许可证(GPL)版本2或3,请参阅license.md