Symfony безопасность json_login добавить настраиваемое поле / контроллер аутентификатора - PullRequest
0 голосов
/ 25 мая 2020

Мне нужно добавить дополнительное поле к json логину, в настоящее время я могу POST a _username и _password на мою login_check конечную точку, но мне также нужно отправить _school_name так же имя пользователя можно использовать в разных школах.

Я использую json_login (https://symfony.com/doc/current/security/json_login_setup.html) с пакетом lexik jwt. Должен ли я создать собственный контроллер для этого или GuardAuthenticator?

Я пытался расширить AbstractGuardAuthenticator, и я попробовал AbstractFormLoginAuthenticator, но они оба не работают для меня. По умолчанию я использовал это:

    login:
      pattern:  ^/api/v1/token
      stateless: true
      anonymous: true
      user_checker: App\Security\UserChecker
      json_login:
        check_path: /api/v1/token/login
        success_handler: lexik_jwt_authentication.handler.authentication_success
        failure_handler: lexik_jwt_authentication.handler.authentication_failure

Затем я добавил свой собственный Guard:

    login:
      pattern:  ^/api/v1/token
      stateless: true
      anonymous: true
      user_checker: App\Security\UserChecker
      guard:
        authenticators:
          - App\Security\BaseAuthenticator
<?php

namespace App\Security;


use App\Entity\Client;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;

class BaseAuthenticator extends AbstractGuardAuthenticator
{
    const LOGIN_ROUTE = 'login_check';

    private EntityManagerInterface $entityManager;
    private UrlGeneratorInterface $urlGenerator;
    private CsrfTokenManagerInterface $csrfTokenManager;
    private UserPasswordEncoderInterface $passwordEncoder;

    public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
    {
        $this->entityManager = $entityManager;
        $this->urlGenerator = $urlGenerator;
        $this->csrfTokenManager = $csrfTokenManager;
        $this->passwordEncoder = $passwordEncoder;
    }

    /**
     * @param Request $request
     * @return bool
     */
    public function supports(Request $request)
    {
        if ($request->attributes->get('_route') !== static::LOGIN_ROUTE) {
            return false;
        }

        if (!$request->isMethod(Request::METHOD_POST)) {
            return false;
        }

        return true;
    }

    /**
     * @param Request $request
     * @return mixed
     */
    public function getCredentials(Request $request)
    {
        return [
            'client_name' => $request->request->get('client_name'),
            'username' => $request->request->get('username'),
            'password' => $request->request->get('password')
        ];
    }

    /**
     * @param mixed $credentials
     * @param UserProviderInterface $userProvider
     * @return UserInterface|null
     */
    public function getUser($credentials, UserProviderInterface $userProvider)
    {
        $userRepository = $this->entityManager->getRepository(User::class);
        $clientRepository = $this->entityManager->getRepository(Client::class);

        $client = $clientRepository->findOneBy([
            'name' => $credentials['client_name']
        ]);

        if (!$client instanceof Client) {
            throw new CustomUserMessageAuthenticationException('Client not found');
        }

        $user = $userRepository->findOneBy([
            'client_id' => $client->getId(),
            'username' => $credentials['username']
        ]);

        if (!$user instanceof User) {
            throw new CustomUserMessageAuthenticationException('User not found');
        }

        return $user;
    }

    /**
     * @param mixed $credentials
     * @param UserInterface $user
     * @return bool
     */
    public function checkCredentials($credentials, UserInterface $user)
    {
        return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
    }

    /**
     * @param Request $request
     * @param TokenInterface $token
     * @param string $providerKey
     * @return Response|null
     */
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
    {
        return null;
    }

    /**
     * @param Request $request
     * @param AuthenticationException|null $authException
     * @return Response
     */
    public function start(Request $request, AuthenticationException $authException = null)
    {
        $data = [
            // you might translate this message
            'message' => 'Authentication Required'
        ];

        return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
    }

    /**
     * @param Request $request
     * @param AuthenticationException $exception
     * @return JsonResponse
     */
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        $data = [
            // you may want to customize or obfuscate the message first
            'message' => strtr($exception->getMessageKey(), $exception->getMessageData())

            // or to translate this message
            // $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
        ];

        return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
    }

    /**
     * @return bool
     */
    public function supportsRememberMe()
    {
        return false;
    }
}

Спасибо!

...