Я работаю над мини-веб-проектом и создаю его в symfony, поэтому после того, как я создал форму регистрации и входа в систему, я понял, что после регистрации пользователь не будет аутентифицирован напрямую, поэтому я провел небольшое исследование, чтобы увидеть, как это работает. но я столкнулся с некоторыми проблемами, и я новичок в этой структуре. Вот код контроллера (в моем приложении класс пользователей называется Players, потому что я разрабатываю побег)
<?php
namespace App\Controller;
use App\Entity\Items;
use App\Entity\Players;
use App\Entity\Inventaire;
use App\Security\TokenAuthenticator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
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 App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Http\HttpUtils;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
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;
}
}
?>
И, наконец, файл security.yaml
security:
encoders:
App\Entity\Players:
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: App\Entity\Players
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: App\Security\authentication_failure_handler
csrf_token_generator: security.csrf.token_manager
failure_path: home
guard:
authenticators:
- App\Security\TokenAuthenticator
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()" не имеет подсказки типа, его значение необходимо указать явно.
Заранее спасибо всем и хорошего дня.
https://symfony.com/doc/current/service_container/autowiring.html
Autowiring позволяет управлять сервисами в контейнере с минимальной настройкой. Он читает подсказки типа в вашем конструкторе (или других методах) и автоматически передает правильные службы каждому методу. Автосвязывание Symfony спроектировано так, чтобы быть предсказуемым: если не совсем ясно, какую зависимость следует передать, вы увидите исключение, требующее действия.
Вы должны указать, что ваши аргументы переданы конструктору, чтобы symfony мог передать их вам автоматически благодаря автосвязыванию:
// others uses
use Symfony\Component\Routing\RouterInterface;
class TokenAuthenticator extends AbstractGuardAuthenticator
{
private $em;
protected $router;
public function __construct(EntityManagerInterface $em, HttpUtils $httpUtils, RouterInterface $router)
{
$this->em = $em;
$this->router = $router;
}
Или, если вы хотите просто генерировать URL-адреса, вы не можете использовать UrlGeneratorInterface вместо маршрутизатора:
// ...
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
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'));
}
Это сработало! Спасибо за вашу помощь, я ценю это.