Symfony security json_login add custom field/authenticator controller

i need to add an extra field to the json login, currently i can POST a _username and _password to my login_check endpoint but i also need to send a _school_name so the same username can be used in different schools.

I am using the json_login (https://symfony.com/doc/current/security/json_login_setup.html) with the lexik jwt bundle. Should i create a custom controller for this or a GuardAuthenticator?

I tried extending the AbstractGuardAuthenticator and i tried the AbstractFormLoginAuthenticator but they are both not working for me. By default i used this:

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

Then i added my custom Guard:

    login:
      pattern:  ^/api/v1/token
      stateless: true
      anonymous: true
      user_checker: AppSecurityUserChecker
      guard:
        authenticators:
          - AppSecurityBaseAuthenticator
<?php

namespace AppSecurity;


use AppEntityClient;
use AppEntityUser;
use DoctrineORMEntityManagerInterface;
use SymfonyComponentHttpFoundationJsonResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingGeneratorUrlGeneratorInterface;
use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;
use SymfonyComponentSecurityCoreEncoderUserPasswordEncoderInterface;
use SymfonyComponentSecurityCoreExceptionAuthenticationException;
use SymfonyComponentSecurityCoreExceptionCustomUserMessageAuthenticationException;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityCsrfCsrfTokenManagerInterface;
use SymfonyComponentSecurityGuardAbstractGuardAuthenticator;

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;
    }
}

Thanks!

Source: Symfony Questions

Was this helpful?

0 / 0

Leave a Reply 0

Your email address will not be published. Required fields are marked *