nepada/security-annotations

Nette 演示器和组件的安全注解。

v5.1.1 2024-04-19 16:42 UTC

README

Build Status Coverage Status Downloads this Month Latest stable

安装

通过 Composer

$ composer require nepada/security-annotations

config.neon 中注册扩展

extensions:
    securityAnnotations: Nepada\Bridges\SecurityAnnotationsDI\SecurityAnnotationsExtension

使用

此包建立在 Nette 组件的标准访问授权之上,即 Nette\Application\UI\Component::checkRequirements() 方法。在调用任何组件/演示器信号处理程序之前,以及在演示器 startupaction<>render<> 方法之前,都会调用此方法。

使用此包,您可以通过任何提到的方法或演示器类的属性来指定访问规则。要启用此功能,简单地在任何演示器或组件中使用 SecurityAnnotations 特性,并确保通过 injectRequirementsChecker() 注入 RequirementsChecker 服务 - 在默认 Nette 配置中,这应该适用于演示器,但您需要处理组件,例如通过启用注入调用。

示例

use Nepada\SecurityAnnotations\Annotations\Allowed;
use Nepada\SecurityAnnotations\Annotations\LoggedIn;
use Nepada\SecurityAnnotations\Annotations\Role;

/**
 * To access this presenter the user must be logged in.
 */
 #[LoggedIn]
class SecuredPresenter extends Nette\Application\UI\Presenter
{

    use Nepada\SecurityAnnotations\SecurityAnnotations;

    #[Role("admin", "superadmin")]
    public function actionForAdmins(): void
    {
        // Only users with role admin or superadmin are allowed here.
    }

     #[Allowed(resource: "world", privilege: "destroy")]
    public function handleDestroyWorld(): void
    {
        // Only users with specific permission are allowed to call this signal.
    }

}

属性和它们强制执行的规则可以完全自定义(见下文),但是默认设置包含三个预定义的规则

  • LoggedIn - 检查用户是否已登录。
  • Role("admin", "superadmin") - 检查用户是否至少拥有其中一个指定的角色。如果您使用 Nette\Security\Permission 作为您的授权者,那么将考虑角色继承,即拥有至少一个继承自指定角色之一的角色的用户也被允许。
  • Allowed(resource: "world", privilege: "destroy") - 检查用户是否至少拥有一个角色,该角色在指定的资源上被授予了指定的权限。

保护组件

正确保护组件是一项棘手的工作,请看以下示例

use Nepada\SecurityAnnotations\Annotations\LoggedIn;

class SecuredPresenter extends Nette\Application\UI\Presenter
{

    use Nepada\SecurityAnnotations\SecurityAnnotations;

    #[LoggedIn]
    public function actionDefault(): void
    {
        // ...
    }

    protected function createComponentForm(): Nette\Application\UI\Form
    {
        $form = new Nette\Application\UI\Form();
        $form->addSubmit('Do something dangerous');
        $form->onSuccess[] = function (Nette\Application\UI\Form $form): void {
            // ...
        };
        return $form;
    }

}

保护 action<>(或 render<>)方法是不够的!只需在你的路由器中有一个通用的路由,例如一个非常常见的 Route('<presenter>/<action>'),任何人都可以通过向 /secured/foo URL 发送 POST 请求来成功提交表单。

在创建组件时,您应该始终检查用户的权限。为了使您的生活更加轻松,有一个 SecuredComponents 特性,它在调用组件工厂之前调用标准的 Nette\Application\UI\Component::checkRequirements() 方法(从 nette/application 3.2.2 开始,Nette 本身执行此检查,使该特性变得过时)。结合 SecurityAnnotations,它允许您通过 createComponent<> 方法上的属性来控制对组件的访问。

自定义访问验证器

  • 您可以通过 enableDefaultValidators: false 禁用默认的验证器集。
  • 您还可以在 validators 配置部分中定义自己的验证器,即实现 Nepada\SecurityAnnotations\AccessValidators\AccessValidator 接口的服务。
securityAnnotations:
    enableDefaultValidators: false # disable default set of validators
    validators:
        - MyRoleAccessValidator # define validator by class name
        - @fooAccessValidator # define validator by service reference
        
services:
    fooAccessValidator: FooAccessValidator(%fooParameter%)

访问验证器是如何工作的?

每个访问验证器都实现了 Nepada\SecurityAnnotations\AccessValidators\AccessValidator 接口。访问验证器通过其公共 API 指定它支持的属性类型。

在检查需求时,PHP 属性逐个传递给相关访问验证器进行审查。根据属性值,验证器决定拒绝访问(抛出 Nette\Application\BadRequestException),或授予访问(不抛出异常)。