Аутентификация Symfony после регистрации

#php #symfony

#php #symfony

Вопрос:

Я работаю над мини-веб-проектом и создаю его на symfony, поэтому после создания формы регистрации и входа в систему я понял, что после регистрации пользователь не будет аутентифицироваться напрямую, поэтому я провел некоторое исследование, чтобы понять, как это работает, но я столкнулся с некоторыми проблемами, и я новичок в этой среде. Вот код контроллера (класс users в моем приложении называется Players, потому что я разрабатываю escape-игру)

 <?php

namespace AppController;
use AppEntityItems;
use AppEntityPlayers;
use AppEntityInventaire;
use AppSecurityTokenAuthenticator;
use DoctrineORMEntityManagerInterface;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingAnnotationRoute;
use SymfonyComponentSecurityGuardGuardAuthenticatorHandler;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentSecurityCoreEncoderUserPasswordEncoderInterface;


class PlayerController extends AbstractController

{
    private $em;
public function __construct(EntityManagerInterface $entityManager)
{
    
    $this->em = $entityManager;
}
/**
 * @Route("/player", name="player")
 */
public function index(): Response
{
    return $this->render('player/index.html.twig', [
        'controller_name' => 'PlayerController',
    ]);
}
/**
 * @Route("/login_Player", name="login_Player")
 */
public function loginPlayer(){
    return $this->render("app/player_interface.html.twig");
}
/**
 * @Route("/redirect_player", name="redirect_player")
 */
public function redirectPlayer(){
    $player = $this->getUser();
    if($player){
        return $this->render("app/player_interface.html.twig",['player'=>$player]);
    }
    else{
        return $this-render("app/home.html.twig");
    }
    
}

/**
 * @Route("/logout_Player", name="logout_Player")
 */
public function logoutPlayer(){
    return $this->render("app/home.html.twig");
}
/**
 * @Route("/create_interface", name="create_Player")
 */
public function createPlayer(Request $request,EntityManagerInterface $em,UserPasswordEncoderInterface $encoder,GuardAuthenticatorHandler $guardHandler,TokenAuthenticator $authenticator): Response
{
    $repository = $this->getDoctrine()->getRepository(Players::class);
    if($request->request->count()>0){
        if(($repository->findBy(["username"=>$request->request->get("pseudo")])) || ($repository->findBy(["email"=>$request->request->get("mail")]))){
            return $this->render("app/home.html.twig",["msg"=>"Id ou mail déja utilisé!"]);
        }
        else{
            $coord=[48.8413672,2.4223428];
            $player = new Players();
            $player->setUsername($request->request->get("pseudo"))
                   ->setPassword($request->request->get("pass"))
                   ->setEmail($request->request->get("mail"));
            $player->setLongitude($coord[1]);
            $player->setLatitude($coord[0]);
            $inventaire=new Inventaire();
            $inventaire->setPlayerId($player);
            $player->setInventaire($inventaire);
            $this->em=$em;
            $hash=$encoder->encodePassword($player, $player->getPassword());
            $player->setPassword($hash);
            $em->persist($player);
            $em->persist($inventaire);
            $em->flush();
            return $guardHandler->authenticateUserAndHandleSuccess($player,$request,$authenticator,'main');
            //return $this->render("app/player_interface.html.twig",['player'=>$player]);//'inventaire'=>$inventaire]);
        }

    }

}
/**
 * @Route("/add_item",name="add_item")
 */
public function addItem(Request $request,EntityManagerInterface $em){
    if ($request->isXmlHttpRequest()){
        $this->em=$em;
        $player = $this->getUser();
        $inventaire=$player->getInventaire();
        $item=new Items();
        $item->setDescription($request->request->get("description"))
             ->setVisibility($request->request->get("visibility"))
             ->setNiveau($request->request->get("icon_id"));
        $inventaire->addItemId($item);
        $em->flush();
        return new JsonResponse(array("player"=>$player,"inventaire"=>$inventaire->getItem_id()));
    }
    else{
        return $this->render("app/player_interface.html.twig");
    }
}

/**
 * @Route("/move_player",name="move_player")
 */
public function movePlayer(Request $request,EntityManagerInterface $em){
    if ($request->isXmlHttpRequest()){
        $this->em=$em;
        $player = $this->getUser();
        $player->setLongitude($request->request->get("longitude"))
               ->setLatitude($request->request->get("latitude"));
        $em->flush();
        return new JsonResponse(array("player"=>$player));
    }
    else{
        return $this->render("app/player_interface.html.twig");
    }

}
/**
 * @Route("affiche_scenario", name="affiche_scenario")
 */
public function afficheScenario(Request $request){
    if ($request->isXmlHttpRequest()){
        $repository = $this->getDoctrine()->getRepository(Scenarios::class);
        return new JsonResponse($repository->findBy($request->request->get("num_scenario")));
    }
    else{
        return $this->render("app/player_interface.html.twig");
    }
}
}
?>
 

и это класс tokenauthenticator:

     <?php
// src/Security/TokenAuthenticator.php
namespace AppSecurity;

use AppEntityUser;
use DoctrineORMEntityManagerInterface;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentSecurityHttpHttpUtils;
use SymfonyComponentHttpFoundationJsonResponse;
use SymfonyComponentHttpFoundationRedirectResponse;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityGuardAbstractGuardAuthenticator;
use SymfonyComponentSecurityCoreExceptionAuthenticationException;
use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;

class TokenAuthenticator extends AbstractGuardAuthenticator
{
    private $em;
    protected $router;

public function __construct(EntityManagerInterface $em,HttpUtils $httpUtils, $router)
{
    $this->em = $em;
    $this->router = $router;
}

/**
 * Called on every request to decide if this authenticator should be
 * used for the request. Returning `false` will cause this authenticator
 * to be skipped.
 */
public function supports(Request $request)
{
    return $request->headers->has('X-AUTH-TOKEN');
}

/**
 * Called on every request. Return whatever credentials you want to
 * be passed to getUser() as $credentials.
 */
public function getCredentials(Request $request)
{
    return $request->headers->get('X-AUTH-TOKEN');
}

public function getUser($credentials, UserProviderInterface $userProvider)
{
    if (null === $credentials) {
        // The token header was empty, authentication fails with HTTP Status
        // Code 401 "Unauthorized"
        return null;
    }

    // The "username" in this case is the apiToken, see the key `property`
    // of `your_db_provider` in `security.yaml`.
    // If this returns a user, checkCredentials() is called next:
    return $userProvider->loadUserByUsername($credentials);
}

public function checkCredentials($credentials, UserInterface $user)
{
    // Check credentials - e.g. make sure the password is valid.
    // In case of an API token, no credential check is needed.

    // Return `true` to cause authentication success
    return true;
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
    
        /*if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
            return new RedirectResponse($targetPath);
        }*/
        return new RedirectResponse($this->router->generate('redirect_player'));
        

    
}

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

/**
 * Called when authentication is needed, but it's not sent
 */
public function start(Request $request, AuthenticationException $authException = null)
{
    $data = [
        // you might translate this message
        'message' => 'Authentication Required'
    ];

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

public function supportsRememberMe()
{
    return false;
    }
}
?>
 

И, наконец, безопасность.файл yaml

 security:
encoders:
    AppEntityPlayers:
        algorithm: bcrypt
    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers

providers:
    users_in_memory: { memory: null }
    in_database:
        entity:
            class: AppEntityPlayers
            property: username
firewalls:
dev:
    pattern: ^/(_(profiler|wdt)|css|images|js)/
    security: false
main:
    anonymous: true
    lazy: true
    #provider: users_in_memory
    provider: in_database

    form_login:
        login_path: login_Player
        check_path: login_Player
        #failure_handler: AppSecurityauthentication_failure_handler
        csrf_token_generator: security.csrf.token_manager
        failure_path: home
    guard:
        authenticators:
            - AppSecurityTokenAuthenticator
    logout:
        path: logout_Player
        target: home



    # activate different ways to authenticate
    # https://symfony.com/doc/current/security.html#firewalls-authentication



      # https://symfony.com/doc/current/security/impersonating_user.html
        # switch_user: true

# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
    # - { path: ^/admin, roles: ROLE_ADMIN }
    # - { path: ^/profile, roles: ROLE_USER }
 

Класс TokenAuthenticator я нашел его в symfony и в другом руководстве, поэтому я не совсем понимаю механизм, и когда я пытаюсь зарегистрировать пользователя сейчас, приложение показывает мне ошибку:
Невозможно выполнить автозапуск службы «App Security TokenAuthenticator»: аргумент «$router» метода «__construct()» не имеет подсказки типа, вы должны явно настроить его значение.

Заранее всем спасибо и хорошего дня.

Ответ №1:

https://symfony.com/doc/current/service_container/autowiring.html

Автоматическое подключение позволяет управлять службами в контейнере с минимальной настройкой. Он считывает подсказки типа в вашем конструкторе (или других методах) и автоматически передает правильные сервисы каждому методу. Автозапуск Symfony разработан так, чтобы быть предсказуемым: если не совсем ясно, какая зависимость должна быть передана, вы увидите исключение, подлежащее действию.

Вы должны ввести подсказку о своих аргументах, переданных конструктору, чтобы symfony мог передать их вам автоматически благодаря автозапуску:

 
// others uses
use SymfonyComponentRoutingRouterInterface;

class TokenAuthenticator extends AbstractGuardAuthenticator
{
    private $em;
    protected $router;

public function __construct(EntityManagerInterface $em, HttpUtils $httpUtils, RouterInterface $router)
{
    $this->em = $em;
    $this->router = $router;
}
 

Или, если вы хотите, чтобы juste генерировал URL-адреса, вы не можете использовать UrlGeneratorInterface вместо маршрутизатора:

 
// ...
use SymfonyComponentRoutingGeneratorUrlGeneratorInterface;

class TokenAuthenticator extends AbstractGuardAuthenticator
{
    private $em;
    protected $urlGenerator;

public function __construct(EntityManagerInterface $em, HttpUtils $httpUtils, UrlGeneratorInterface $urlGenerator)
{
    $this->em = $em;
    $this->urlGenerator = $urlGenerator;
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
    return new RedirectResponse($this->urlGenerator->generate('redirect_player'));
}

 

Комментарии:

1. Это сработало! Спасибо за вашу помощь, я ценю это.