Авторизация

Когда любой из поставщикой аутентификации (см. Поставщики аутентификации) подтвердил все-еще-неавторизованный токен, будет возващён аутентифицированный токен. Слушатель аутентификации установит этот токен напрямую в TokenStorageInterface, используя его метод setToken().

С этого момента пользователь будет аутентифицирован, т.е. идентифицирован. Теперь, другие части приложения могут использовать токен, чтобы решить, может ли пользователь запрашивать определённый URI или изменять определённый объект. Это решение будет принято экземпляром AccessDecisionManagerInterface.

Решение авторизации будет всегда основываться на нескольких вещах:

  • Текущем токене
    Например, метод токена getRoles() может быть использован для извлечения ролей текущего пользователя (например, ROLE_SUPER_ADMIN), или решение может быть основано на классе токена.
  • Наборе атрибутов
    Каждый атрибут представляет определённое право, которое должен иметь пользователь, к примеру ROLE_ADMIN, чтобы гарантировать, что пользователь является администратором.
  • Объекте (опционально)
    Любой объект, для которого нужно проверять контроль доступа, вроде объекта статьи или комментария.

Доступ к менеджеру решений

Так как принятие решения о том, авторизирован ли пользователь производить определённое действие, может быть достаточно сложным процессом, сам стандартный AccessDecisionManager зависит от нескольких избирателей и выносит финальный вердикт, основываясь на всех голосах (положительных, отрицательных или нейтральных), который он получил. Он признаёт несколько стратегий:

affirmative (по умолчанию)
предоставлять доступ, как только есть один избиратель, предоставляющий доступ;
consensus
предоставлять доступ, если больше избирателей предоставляют доступ, чем отказывают в нём;
unanimous
предоставлять доступ только, если ни один из избираетелей не отказал в нём;
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;

// экземпляры Symfony\Component\Security\Core\Authorization\Voter\VoterInterface
$voters = array(...);

// один из "affirmative", "consensus", "unanimous"
$strategy = ...;

// предоставлять ли доступ, если все избиратели удержались
$allowIfAllAbstainDecisions = ...;

// предоставлять ли доступ, когда нет большинства (применимо только к стратегии "consensus")
$allowIfEqualGrantedDeniedDecisions = ...;

$accessDecisionManager = new AccessDecisionManager(
    $voters,
    $strategy,
    $allowIfAllAbstainDecisions,
    $allowIfEqualGrantedDeniedDecisions
);
Вы можете изменить стратегию по умолчанию в конфигурации.

Избиратели

Избиратели являются экземплярами класса VoterInterface, что означает, что они должны реализовывать несколько методов, что позволяет менеджеру решений использовать их:

vote(TokenInterface $token, $object, array $attributes)
этот метод будет проводить голосование и возвращать значение, равное одной из констант класса VoterInterface, т.е. VoterInterface::ACCESS_GRANTED, VoterInterface::ACCESS_DENIED или VoterInterface::ACCESS_ABSTAIN;

Компонент Security содержит несколько стандартных избирателей, которые охватывают множество случаев применения:

AuthenticatedVoter

Избиратель AuthenticatedVoter поддерживает атрибуты IS_AUTHENTICATED_FULLY, IS_AUTHENTICATED_REMEMBERED, и IS_AUTHENTICATED_ANONYMOUSLY и предоставляет доступ, основываясь на текущем уровне аутентификации, т.е. является ли пользователь полностью аутентифицированным, или только за счёт куки "запомнить меня", или вообще аутентифицирован анонимно?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver;
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;

$trustResolver = new AuthenticationTrustResolver(AnonymousToken::class, RememberMeToken::class);

$authenticatedVoter = new AuthenticatedVoter($trustResolver);

// экземпляр Symfony\Component\Security\Core\Authentication\Token\TokenInterface
$token = ...;

// любой объект
$object = ...;

$vote = $authenticatedVoter->vote($token, $object, array('IS_AUTHENTICATED_FULLY'));

RoleVoter

RoleVoter поддерживает атрибуты, начинающиеся с ROLE_ и предоставляет доступ пользователю, если все обязательные атрибуты ROLE_* могут быть найдены в массиве ролей, возвращённых методом токена getRoles():

1
2
3
4
5
use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter;

$roleVoter = new RoleVoter('ROLE_');

$roleVoter->vote($token, $object, array('ROLE_ADMIN'));

RoleHierarchyVoter

RoleHierarchyVoter расширяет RoleVoter и предоставляет некоторый дополнительный функционал: он знает, как работать с иерархией ролей. Например, роль ROLE_SUPER_ADMIN может иметь подроли ROLE_ADMIN и ROLE_USER, чтобы если определённый объект требует, чтобы у пользователя была роль ROLE_ADMIN, он предоставлял доступ пользователям, которые по факту имеют роль ROLE_ADMIN, а также пользователям, которые имеют роль ROLE_SUPER_ADMIN:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
use Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter;
use Symfony\Component\Security\Core\Role\RoleHierarchy;

$hierarchy = array(
    'ROLE_SUPER_ADMIN' => array('ROLE_ADMIN', 'ROLE_USER'),
);

$roleHierarchy = new RoleHierarchy($hierarchy);

$roleHierarchyVoter = new RoleHierarchyVoter($roleHierarchy);

Note

Когда вы делаете собственного избирателя, вы можете конечно же использовать его конструктор, чтобы внедрить любые зависимости, необходимые для принятия решения.

Роли

Роли - это объекты, которые предоставляют выражения определённому праву пользователя. Единственным требованием является,чтобы они реализовали RoleInterface, что означает, что они должны также иметь метод getRole(), который возвращает строковое представление самой роли. По умолчанию, Role просто возвращает свой первый аргумент конструктора:

1
2
3
4
5
6
use Symfony\Component\Security\Core\Role\Role;

$role = new Role('ROLE_ADMIN');

// отображает 'ROLE_ADMIN'
var_dump($role->getRole());

Note

Больщинство токенов аутентификации расширяются из AbstractToken, что означает, что роли, данные его конструктору, будут автоматически преобразованы из строк в эти простые объекты Role.

Использование менеджера решений

Слушатель доступа

Менеджер решений доступа может быть использован в любой момент запроса, чтобы решить, имеет ли текущий пользователь право доступа к заданному источнику. Одним необязательным, но полезным методом для ограничения доступа, основываясь на схеме URL, является AccessListener, который является одним из слушателей брандмауэра (см. Слушатели брандмауэра), он вызывается для каждого запроса, совпадающего с картой брандмауэра (см. Брандмауэр для HTTP запросов).

Он использует карту доступа (которая должна быть экземпляром AccessMapInterface), содержащую сопоставиели запросов и соответствующий набор атрибутов, которые требуются для того, чтобы текущий пользователь получил доступ к приложению:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
use Symfony\Component\Security\Http\AccessMap;
use Symfony\Component\HttpFoundation\RequestMatcher;
use Symfony\Component\Security\Http\Firewall\AccessListener;

$accessMap = new AccessMap();
$requestMatcher = new RequestMatcher('^/admin');
$accessMap->add($requestMatcher, array('ROLE_ADMIN'));

$accessListener = new AccessListener(
    $securityContext,
    $accessDecisionManager,
    $accessMap,
    $authenticationManager
);

Проверщик авторизации

Менеджер решений доступа также доступен в других частях приложения через метод isGranted() класса AuthorizationChecker. Вызов этого метода напрямую делегирует вопрос менеджеру решений доступа:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

$authorizationChecker = new AuthorizationChecker(
    $tokenStorage,
    $authenticationManager,
    $accessDecisionManager
);

if (!$authorizationChecker->isGranted('ROLE_ADMIN')) {
    throw new AccessDeniedException();
}

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.