Я занят реализацией ACL на уровне класса + поля (classFieldAce) в своем приложении. Кажется, все работает нормально, но я получаю неожиданное поведение от метода isFieldGranted() из ACL. Вот мой код:
// setup ACL
$className = 'Acme\Model\Junk';
$oid = new ObjectIdentity('class', $className);
try {
$acl = $aclProvider->findAcl($oid);
} catch (Exception $e) {
$acl = $aclProvider->createAcl($oid);
$roleUser = new RoleSecurityIdentity('ROLE_USER');
$mask = new MaskBuilder(4); // 4 = EDIT
$acl->insertclassFieldAce('name', $roleUser, $mask->get());
}
$aclProvider->updateAcl($acl);
Все идет нормально. Я назначаю своему пользователю роль "ROLE_USER". Теперь я хочу запустить некоторые проверки (вручную, когда я создаю сервис). Вот код проверки (пока внутри контроллера):
// check the ACL
$className = 'Acme\Model\Junk';
$oid = new ObjectIdentity('class', $className);
$aclProvider = $this->get('security.acl.provider');
try {
$acl = $aclProvider->findAcl($oid);
} catch (...)
все хорошо. Теперь то, что я хочу проверить:
$sids = array();
foreach ($this->getUser()->getRoles() as $role) {
$sids[] = new RoleSecurityIdentity($role);
}
$masks = array();
$masks[] = MaskBuilder::MASK_EDIT;
if ($acl->isFieldGranted('name', $masks, $sids)) {
echo "OK";
} else {
echo "NOT ALLOWED";
}
На данный момент все работает, я получаю вывод «ОК». Единственное, в чем я немного не уверен, так это в очень окольном способе отправки $sids на проверку, поэтому мой первый вопрос будет заключаться в том, есть ли более быстрый способ, кроме ручного создания списка.
Все начинает идти «не так» (как неожиданно), когда я пытаюсь проверить более высокую маску:
$sids = array();
foreach ($this->getUser()->getRoles() as $role) {
$sids[] = new RoleSecurityIdentity($role);
}
$masks = array();
$masks[] = MaskBuilder::MASK_OWNER;
if ($acl->isFieldGranted('name', $masks, $sids)) {
echo "OK";
} else {
echo "NOT ALLOWED";
}
вместо возврата false $acl->isFieldGranted генерирует исключение NoAceFoundException.
Я неправильно проверяю поле, или я должен просто ловить исключения здесь?
Обновление: добавлены журналы:
код проверки изменен на:
$this->get('logger')->debug('XX: ACL retrieved, checking field grants');
try {
if ($acl->isFieldGranted('name', $masks, $sids, true)) {
$this->get('logger')->debug('XX: ACL OK for field :name:');
}
} catch (NoAceFoundException $e) {
$this->get('logger')->debug('XX: ACL NOT OK for field :name: NoAceFoundException thrown');
}
При успешной проверке журналы выглядят следующим образом:
DEBUG - SELECT o.id as acl_id, o.object_identifier, o.parent_object_identity_id,
o.entries_inheriting, c.class_type, e.id as ace_id, e.object_identity_id, e.field_name,
e.ace_order, e.mask, e.granting, e.granting_strategy, e.audit_success, e.audit_failure,
s.username, s.identifier as security_identifier FROM acl_object_identities o INNER JOIN
acl_classes c ON c.id = o.class_id LEFT JOIN acl_entries e ON ( e.class_id = o.class_id AND
(e.object_identity_id = o.id OR e.object_identity_id IS NULL) )
LEFT JOIN acl_security_identities s ON ( s.id = e.security_identity_id ) WHERE (o.id =16)
DEBUG - SELECT t0.name AS name1, t0.roles AS roles2, t0.id AS id3 FROM staff_group t0
INNER JOIN rel_staff_staff_group ON t0.id = rel_staff_staff_group.group_id
WHERE rel_staff_staff_group.staff_id = ? Context: ["242"]
DEBUG - XX: ACL retrieved, checking field grants
DEBUG - XX: ACL OK for field :name:
При неудачной проверке меняется только эта строчка (я сравнивал логи в двух вкладках браузера)
DEBUG - XX: ACL NOT OK for field :name: NoAceFoundException thrown
Нет никакой разницы в регистрации между
$acl->isFieldGranted('name', $masks, $sids)
а также
$acl->isFieldGranted('name', $masks, $sids, true)
Обновление 2:
Я открыл отчет об ошибке в Symfony, и он был исправлен https://github.com/symfony/symfony/issues/9433
var_dump($acl->getClassFieldAces('name'));
перед вашим$acl->isFieldGranted('name', $masks, $sids)
. - person Serge Kvashnin   schedule 16.10.2013