sandstorm / neosacl
Requires
- neos/flow: ^7.0 || ^8.0 || dev-master
- neos/fusion-afx: *
README
此包实现了Neos角色的动态访问控制列表。
主要功能
- 将
RestrictedEditor
切换到仅允许列表的权限方法。通过安装此包,RestrictedEditor
不再允许更改任何内容。 - 通过Neos后端模块配置动态角色。
- 可以在节点树、工作空间和维度上设置权限。
- 权限以合理的默认值和纯累加逻辑可预测地工作。
安装
- 安装包
composer require sandstorm/neosacl
- 运行迁移
./flow doctrine:migrate
- 使用管理员账户登录并访问新的菜单项“动态角色”
开发
(包)初始设置
- 将此包作为
Sandstorm.NeosAcl
克隆到Neos 4.3或更高版本的安装的DistributionPackages中 - 将其添加到
composer.json
中为"sandstorm/neosacl": "*"
- 运行
composer update
初始React设置
cd Resources/Private/react-acl-editor
yarn
yarn dev
然后,登录到Neos的后端,并访问“动态角色”模块。
内部实现细节
实现动态节点权限和方法权限
基本思路如下:钩入PolicyService::emitConfigurationLoaded
,并修改$configuration
数组(引入新的角色和privilegeTargets)。这基本上在运行时工作 - 但是动态方法权限执行存在问题,以下将进行解释,并附上以下图表
方法权限是如何工作的
- 背景:在Flow编译时,
PointcutFilterInterface
的实现可以决定哪些类和方法匹配某个方面。- 这用于
PolicyEnforcementAspect
(强制执行MethodPrivileges
的中心点)。 - 在那里,引用了
MethodPrivilegePointcutFilter
。 MethodPrivilegePointcutFilter
向PolicyService
请求所有配置的MethodPrivilege
- 并确保为这些方法构建AOP代理。
- 这用于
- 副作用:现在,在构建点cut过滤器时,
MethodPrivilegePointcutFilter
还额外构建了一个数据结构methodPermissions
- 该数据结构记住哪些方法注册了哪些MethodPrivileges
。- 此数据结构存储在
Flow_Security_Authorization_Privilege_Method
缓存中。 - 在运行时,对于被
PolicyEnforcementAspect
拦截的类,所有配置的MethodPrivilege
都会被调用 - 它们必须快速决定是否匹配此特定调用点
。 - 这是使用来自
Flow_Security_Authorization_Privilege_Method
缓存的methodPermissions
数据结构完成的。
- 此数据结构存储在
动态添加方法权限的问题是什么
- 如果
MethodPrivilege
在运行时动态定义,则methodPermissions
数据结构将缺少有关此新权限应调用某些方法的信息。 - 注意:您只能为已经被AOP(面向切面编程)增强的调用点动态添加
MethodPrivileges
;否则,代码将永远不会被调用(因为缺少代理)。
我们主要与EditNodePrivilege
等交互 - 那为什么这在这里适用呢?
EditNodePrivilege
有一个内部MethodPrivilege
,负责方法调用执行部分;即如果您没有权限执行,将阻止您调用例如NodeInterface::setProperty()
。
此外,为了让这个想法生效,本包的Policy.yaml
定义了一个通配符Sandstorm.NeosAcl:EditAllNodes
权限目标 - 因此AOP将增强NodeInterface
的相应方法。在任何情况下,这种通配符都是有意义的,因为它将安全框架切换为仅允许列表的方法,使其更容易理解。
- 。
目标
为了使动态策略执行生效,我们需要为动态添加的角色添加自定义内容到methodPermissions
。
实现
使用自定义缓存前端(SecurityAuthorizationPrivilegeMethodCacheFrontend
)进行methodPermissions
的后处理。
实现动态AOP运行时表达式
方法权限内部可以使用动态AOP运行时表达式(如果您检查方法参数)。特别是MethodPrivilege
- 它附加到RemoveNodePrivilege
- 使用以下表达式代码
return 'within(' . NodeInterface::class . ') && method(.*->setRemoved(removed == true))';
removed == true
部分是一个所谓的AOP运行时表达式。
这是使用Flow_Aop_RuntimeExpressions
"缓存"内部实现的,该缓存再次在编译时填充(这是一个讨厌的副作用)。
因此,在我们的情况下,我们需要再次实现一个自定义缓存前端(AopRuntimeExpressionsCacheFrontend
),使用基配置的运行时表达式,该配置是正确存在的。