Feature: #109365 - Introduce module access gates for backend modules
See forge#109365
Description
The previously hardcoded module access checks (
user,
admin,
system) in the backend module registration have been replaced
with an extensible gate system. Each access type is now handled by a dedicated
gate class implementing
Module.
TYPO3 ships three built-in gates that preserve the existing behavior:
User— grants access to admin users and users/groups with explicit module permissions (Gate be_/users. user Mods be_)groups. group Mods Admin— grants access only to admin usersGate System— grants access only to system maintainersMaintainer Gate
Extension authors can register custom gates using the
# PHP attribute. A gate receives the module and the
current backend user and returns one of three results:
Module— access is explicitly allowedAccess Result:: Granted Module— access is explicitly deniedAccess Result:: Denied Module— the gate cannot decide (not responsible for this access type)Access Result:: Abstain
Example: Custom module access gate
namespace MyVendor\MyExtension\Module\AccessGate;
use TYPO3\CMS\Backend\Module\ModuleAccessGateInterface;
use TYPO3\CMS\Backend\Module\ModuleAccessResult;
use TYPO3\CMS\Backend\Module\ModuleInterface;
use TYPO3\CMS\Core\Attribute\AsModuleAccessGate;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
#[AsModuleAccessGate(identifier: 'editor')]
final readonly class EditorGate implements ModuleAccessGateInterface
{
public function decide(
ModuleInterface $module,
BackendUserAuthentication $user
): ModuleAccessResult {
if ($module->getAccess() !== 'editor') {
return ModuleAccessResult::Abstain;
}
// Custom logic: check for a specific user group
return $user->check('groupList', '3')
? ModuleAccessResult::Granted
: ModuleAccessResult::Denied;
}
}
The custom gate can then be referenced in the module registration:
return [
'my_module' => [
'access' => 'editor',
'labels' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang_mod.xlf',
// ...
],
];
Ordering gates
Gates support
before and
after parameters to control their
evaluation order when multiple gates are registered:
#[AsModuleAccessGate(identifier: 'editor', after: ['user'])]
final readonly class EditorGate implements ModuleAccessGateInterface
{
// ...
}
Impact
Extension authors can now define custom module access strategies beyond the
built-in
user,
admin, and
system levels by
implementing
Module and registering it with the
# attribute.
Existing module registrations using the built-in access values continue to work without changes.