#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. Это сработало! Спасибо за вашу помощь, я ценю это.