Как создать пользовательского поставщика пользователей
Дата обновления перевода 2023-06-29
Как создать пользовательского поставщика пользователей
Часть стандартного процесса аутентификации Symfony зависит от "поставщико
пользователей". Когда пользователь отправляет имя пользователя и пароль, слой
аутентификации просит сконфигурированного поставщика пользователей вернуть объект
пользователя для данного имени пользователя. Потом Symfony проверяет, правильный
ли пароль у этого пользователя и генерирует токен безопасности, чтобы пользователь
оставался в системе во время текущей сессии. Сразу после установки, Symfony имеет
четыре поставщика пользователей: memory
, entity
, ldap
и chain
. В
этой статье вы увидите, как вы можете создать собственного поставщика пользователей,
который может быть полезен, если доступ к вашим пользователям получен через пользовательскую
DB, файл, или, как показано в этом примере, через веб-сервис.
Создайте класс пользователя
Для начала, не зависимо от того, откуда идут данные пользователя, вам
понадобится создать класс User
, который представляет эти данные. User
может выглядеть так, как вам этого хочется, и содержать любые данные.
Единственное требование - чтобы он реализовывал
UserInterface.
Методы в этом интерфейсе поэтому должны быть определены в пользовательском классе
пользователя getRoles(),
getPassword(),
getSalt(),
getUsername(),
eraseCredentials().
Также может быть полезно реализовать интерфейс
EquatableInterface, который
определяет метод для проверки, равен ли пользователь текущему пользователю. Этот
интерфейс требует метод isEqualTo().
Вот как ваш класс WebserviceUser
выглядит в действии:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
// src/Security/User/WebserviceUser.php
namespace App\Security\User;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;
class WebserviceUser implements UserInterface, EquatableInterface
{
private $username;
private $password;
private $salt;
private $roles;
public function __construct($username, $password, $salt, array $roles)
{
$this->username = $username;
$this->password = $password;
$this->salt = $salt;
$this->roles = $roles;
}
public function getRoles()
{
return $this->roles;
}
public function getPassword()
{
return $this->password;
}
public function getSalt()
{
return $this->salt;
}
public function getUsername()
{
return $this->username;
}
public function eraseCredentials()
{
}
public function isEqualTo(UserInterface $user)
{
if (!$user instanceof WebserviceUser) {
return false;
}
if ($this->password !== $user->getPassword()) {
return false;
}
if ($this->salt !== $user->getSalt()) {
return false;
}
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}
}
Если у вас есть больше информации о ваших пользователях, например, "имя",
тогда вы можете добавить поле firstName
для хранения этих данных.
Создайте поставщика пользователей
Теперь, когда у вас есть класс User
, вы создадите поставщика пользователей,
который будет брать информацию о пользователе с какого-то веб-сервиса, создавать
объект WebserviceUser
и наполнять его данными.
Поставщик пользователей - это простой PHP-класс, который должен реализовать
UserProviderInterface,
который требует определения трёх методов: loadUserByUsername($username)
,
refreshUser(UserInterface $user)
, и supportsClass($class)
. Чтобы
узнать больше деталей, смотрите
UserProviderInterface.
Вот пример того, как это может выглядеть:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
// src/Security/User/WebserviceUserProvider.php
namespace App\Security\User;
use App\Security\User\WebserviceUser;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
class WebserviceUserProvider implements UserProviderInterface
{
public function loadUserByUsername($username)
{
// тут сделайте вызов к вашему веб-сервису
$userData = ...
// представьте, чтоон возвращает массив при удачной операции, и false, если пользователя нет
if ($userData) {
$password = '...';
// ...
return new WebserviceUser($username, $password, $salt, $roles);
}
throw new UsernameNotFoundException(
sprintf('Username "%s" does not exist.', $username)
);
}
public function refreshUser(UserInterface $user)
{
if (!$user instanceof WebserviceUser) {
throw new UnsupportedUserException(
sprintf('Instances of "%s" are not supported.', get_class($user))
);
}
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class)
{
return WebserviceUser::class === $class;
}
}
Создайте сервис для поставщика пользователей
Теперь вы сделаете поставщика пользоваталей доступным в качестве сервиса. Если вы используете конфигурацию services.yaml по умолчанию , это произойдёт автоматически.
Настройка security.yaml
Всё сходится вместе в вашей конфигурации безопасности. Добавьте поставщика пользователей
к списку поставщиков в конфигурации безопасности. Выберите имя для поставщика пользоваталей
(например, "webservice") и укажите id
сервиса, который вы только что определили.
1 2 3 4 5 6 7
# config/packages/security.yaml
security:
# ...
providers:
webservice:
id: App\Security\User\WebserviceUserProvider
Symfony также должна знать, как шифровать пароли, которые поставляются пользователями сайта, например, заполняя форму входа в систему. Вы можете сделать это добавив строку к разделу "кодировщики" в вашей конфигурации безопасности:
1 2 3 4 5 6
# config/packages/security.yaml
security:
# ...
encoders:
App\Security\User\WebserviceUser: bcrypt
Значение здесь должно соответствовать с тем, как изначально были зашифрованы
паролипри создании ваших пользователей (и тем, как были созданы пользователи).
Когда пользователь отправляет свой пароль, он зашифровывается с использованием
этого алгоритма и результат сравнивается с хешированным паролем, возвращённым
методом getPassword()
.