Api аутентификация на symfony 4
Пытаюсь сделать REST API сервис на symfony(без использования api platform). Дошел до аутентификации пользователя. Я правильно понимаю алгоритм работы,
1) Проходим обычную аутентификацию
2) Создаем apiKey и записываем его в бд
3) Возвращаем клиенту этот apiKey
4) При каждом обращении клиента к серверу проверяем валидность apiKey
?
Если да, то как это все правильно сделать? Какие сервисы использовать и т.д. начиная с первого шага. Желательно использовать минимум сторонних сервисов, а только то что рекомендовано самими разработчиками symfony
Ответы (1 шт):
1) устанавливаете компонент безопасности composer require symfony/security-bundle
2) расширяете класс пользователя от интерфейса пользователя
UserEntity extends Symfony\Component\Security\Core\User\UserInterface UserInterface
Сущность пользователя должна содержать свойство apiToken
3) в файле config/packages/security.yaml добавляете сроки
providers:
user:
entity:
class: App\Entity\UserEntity
property: email
4) подразумевается, что у вас есть репозиторий для класса пользователя
5) создаем аутефикатор, добавляем в конструктор репозиторий
use App\Repository\UserRepository;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AuthenticatorInterface;
use Symfony\Component\Security\Guard\Token\PostAuthenticationGuardToken;
class ApiTokenAuthenticator implements AuthenticatorInterface
{
/**
* @var UserRepository
*/
private $userRepo;
public function __construct(UserRepository $userRepo)
{
$this->userRepo = $userRepo;
}
public function start(Request $request, AuthenticationException $authException = null): Response
{
return new JsonResponse(['error' => 'Authentication Required'], Response::HTTP_FORBIDDEN);
}
public function supports(Request $request): bool
{
return $request->headers->has('TOKEN');
}
public function getCredentials(Request $request): ?string
{
return $request->headers->get('TOKEN');
}
public function getUser($token, UserProviderInterface $userProvider): ?UserInterface
{
return $this->userRepo->getByToken($token);
}
public function checkCredentials($credentials, UserInterface $user): bool
{
return true;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response
{
return new JsonResponse(['error' => $exception->getMessage()], Response::HTTP_FORBIDDEN);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
return null;
}
public function supportsRememberMe(): bool
{
return false;
}
public function createAuthenticatedToken(UserInterface $user, $providerKey)
{
return new PostAuthenticationGuardToken($user, $providerKey, $user->getRoles());
}
Я не буду расписывать работу каждого метода, все описания можно почитать в интерфейсе
6) далее идем в config/packages/security.yaml и добавляем (меняем) строки
main:
anonymous: ~
provider: user
guard:
authenticators:
- App\ApiTokenAuthenticator
и чуть ниже:
access_control:
- { path: ^/, methods: [OPTIONS], roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/user, methods: [GET, POST], roles: ROLE_USER }
Далее все запросы к /user вы делаете с заголовком TOKEN,
Сразу скажу, что аутенфикатор необходимо поправить по красоте, например в методе getUser, лучше сразу выбрасывать ошибку 403.