Как создать пользовательского поставщика пользователей¶
Часть стандартного процесса аутентификации Symfony зависит от “поставщико
пользователей”. Когда пользователь отправляет имя пользователя и пароль, слой
аутентификации просит сконфигурированного поставщика пользователей вернуть объект
пользователя для данного имени пользователя. Потом Symfony проверяет, правильный
ли пароль у этого пользователя и генерирует токен безопасности, чтобы пользователь
оставался в системе во время текущей сессии. Сразу после установки, Symfony имеет
четыре поставщика пользователей: memory
, entity
, ldap
и chain
. В
этой статье вы увидите, как вы можете создать собственного поставщика пользователей,
который может быть полезен, если доступ к вашим пользователям получен через пользовательскую
DB, файл, или, как показано в этом примере, через веб-сервис.
Создайте класс пользователя¶
Для начала, не зависимо от того, откуда идут данные пользователя, вам
понадобится создать класс User
, который представляет эти данные. User
может выглядеть так, как вам этого хочется, и содержать любые данные.
Единственное требование - чтобы он реализовывал
UserInterface
.
Методы в этом интерфейсе поэтому должны быть определены в пользовательском классе
пользователя getRoles()
,
getPassword()
,
getSalt()
,
getUsername()
,
eraseCredentials()
.
Также может быть полезно реализовать интерфейс
EquatableInterface
, который
определяет метод для проверки, равен ли пользователь текущему пользователю. Этот
интерфейс требует метод isEqualTo()
.
Вот как ваш класс WebserviceUser
выглядит в действии:
// 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
.
Вот пример того, как это может выглядеть:
// 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
сервиса, который вы только что определили.
- YAML
1 2 3 4 5 6 7
# config/packages/security.yaml security: # ... providers: webservice: id: App\Security\User\WebserviceUserProvider
- XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<!-- config/packages/security.xml --> <?xml version="1.0" encoding="UTF-8"?> <srv:container xmlns="http://symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://symfony.com/schema/dic/services" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <config> <!-- ... --> <provider name="webservice" id="App\Security\User\WebserviceUserProvider" /> </config> </srv:container>
- PHP
1 2 3 4 5 6 7 8 9 10 11 12
// config/packages/security.php use App\Security\User\WebserviceUserProvider; $container->loadFromExtension('security', array( // ... 'providers' => array( 'webservice' => array( 'id' => WebserviceUserProvider::class, ), ), ));
Symfony также должна знать, как шифровать пароли, которые поставляются пользователями сайта, например, заполняя форму входа в систему. Вы можете сделать это добавив строку к разделу “кодировщики” в вашей конфигурации безопасности:
- YAML
1 2 3 4 5 6
# config/packages/security.yaml security: # ... encoders: App\Security\User\WebserviceUser: bcrypt
- XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<!-- config/packages/security.xml --> <?xml version="1.0" encoding="UTF-8"?> <srv:container xmlns="http://symfony.com/schema/dic/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:srv="http://symfony.com/schema/dic/services" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> <config> <!-- ... --> <encoder class="App\Security\User\WebserviceUser" algorithm="bcrypt" /> </config> </srv:container>
- PHP
1 2 3 4 5 6 7 8 9 10 11
// config/packages/security.php use App\Security\User\WebserviceUser; $container->loadFromExtension('security', array( // ... 'encoders' => array( WebserviceUser::class => 'bcrypt', ), // ... ));
Значение здесь должно соответствовать с тем, как изначально были зашифрованы
паролипри создании ваших пользователей (и тем, как были созданы пользователи).
Когда пользователь отправляет свой пароль, он зашифровывается с использованием
этого алгоритма и результат сравнивается с хешированным паролем, возвращённым
методом getPassword()
.
Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.