nepada / security-annotations
Nette 演示器和组件的安全注解。
Requires
- php: >=8.1.0 <8.4
- nette/application: ^3.1.4@dev
- nette/component-model: ^3.0.2@dev
- nette/security: ^3.1@dev
- nette/utils: ^3.2@dev || ^4.0@dev
Requires (Dev)
- mockery/mockery: 1.6.11
- nepada/coding-standard: 7.14.0
- nepada/phpstan-nette-tester: 1.1.0
- nette/bootstrap: >=3.1@dev
- nette/di: ^3.0.6@dev
- nette/http: >=3.0@dev
- nette/schema: ^1.0.3@dev
- nette/tester: 2.5.2
- php-parallel-lint/php-parallel-lint: 1.4.0
- phpstan/phpstan: 1.10.66
- phpstan/phpstan-mockery: 1.1.2
- phpstan/phpstan-nette: 1.2.9
- phpstan/phpstan-strict-rules: 1.5.2
- shipmonk/phpstan-rules: 2.11.3
- spaze/phpstan-disallowed-calls: 3.1.2
Suggests
- nette/di: for integration with Nette DI container
README
安装
通过 Composer
$ composer require nepada/security-annotations
在 config.neon
中注册扩展
extensions: securityAnnotations: Nepada\Bridges\SecurityAnnotationsDI\SecurityAnnotationsExtension
使用
此包建立在 Nette 组件的标准访问授权之上,即 Nette\Application\UI\Component::checkRequirements()
方法。在调用任何组件/演示器信号处理程序之前,以及在演示器 startup
、action<>
和 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
),或授予访问(不抛出异常)。