我已经改变了我的 Web 应用程序的前端,并使用了一些 JavaScript 来动态地将我的登录表单更改为注册表单(只是隐藏了我不想看到的那个)。所以,我有两个表单显示在同一根树枝上,现在我无法提交其中任何一个。当我尝试登录时出现 CSRF 令牌错误,当我尝试注册时出现错误“在数据库中找不到此电子邮件地址”。 如果有人可以帮助我,它会挽救我的一天?
编辑:我看过 HttpKernel 子查询,这是解决我的问题的好方法吗?
我有 2 个模板:1 个用于登录,另一个用于注册。我用第三个给他们打电话,就像这样:
{{render(controller('App\\Controller\\SecurityController::login'))}}
{{ render(controller('App\\Controller\\RegistrationController::register')) }}
在这里你可以看到我的 SecurityController :
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
/**
* @Route("", name="app_loginform")
*/
public function login(AuthenticationUtils $authenticationUtils): Response
{
if ($this->getUser()) {
return $this->redirectToRoute('app_user');
}
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', [
'last_username' => $lastUsername, 'error' => $error
]);
}
/**
* @Route("/logout", name="app_logout")
*/
public function logout()
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
这是我的 RegistrationController :
<?php
namespace App\Controller;
use App\Entity\User;
use App\Form\RegistrationFormType;
use App\Security\EmailVerifier;
use App\Security\UserAuthenticator;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mime\Address;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
class RegistrationController extends AbstractController
{
private $emailVerifier;
public function __construct(EmailVerifier $emailVerifier)
{
$this->emailVerifier = $emailVerifier;
}
/**
* @Route("", name="app_registration")
*/
public function register(
Request $request,
UserPasswordEncoderInterface $passwordEncoder,
GuardAuthenticatorHandler $guardHandler,
UserAuthenticator $authenticator
): Response {
$user = new User();
$form = $this->createForm(RegistrationFormType::class, $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid() && $request->request->has('formRegister')) {
// encode the plain password
$user->setPassword(
$passwordEncoder->encodePassword(
$user,
$form->get('plainPassword')->getData()
)
);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
);
}
return $this->render('registration/register.html.twig', [
'registrationForm' => $form->createView(),
]);
}
}
现在你可以看到我的表格了:
<?php
namespace App\Form;
use App\Entity\User;
use Doctrine\DBAL\Types\StringType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
class RegistrationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'email',
TextType::class,
[
'label' => ' ',
'attr' => [
'placeholder' => 'your@email.com'
],
],
)
->add('agreeTerms', CheckboxType::class, [
'mapped' => false,
'constraints' => [
new IsTrue([
'message' => 'You have to accept conditions',
]),
],
])
->add('plainPassword', PasswordType::class, [
'mapped' => false,
'constraints' => [
new NotBlank([
'message' => 'empty password',
]),
new Length([
'min' => 6,
'minMessage' => 'minimum password : {{ limit }} char',
// max length allowed by Symfony for security reasons
'max' => 4096,
]),
],
'attr' => [
'placeholder' => 'Password'
],
'label' => ' ',
])
->add(
'firstName',
TextType::class,
[
'label' => ' ',
'attr' => [
'placeholder' => 'Firstname'
],
],
)
->add(
'name',
TextType::class,
[
'label' => ' ',
'attr' => [
'placeholder' => 'Name'
],
],
)
->add(
'adress',
TextType::class,
[
'label' => ' ',
'attr' => [
'placeholder' => 'Address'
],
],
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
和注册模板:
{{ form_start(registrationForm) }}
<form class="registration-form-rows" form action="{{ path('app_registration') }}" method="post" id="formRegister">
<div class="name-wrapper">
<div
class="fname-wrapper">
<!-- First Name -->
<div class="fname">
{{ form_row(registrationForm.firstName, {attr:{'class': 'form-control'}})}}
</div>
</div>
<div
class="lname-wrapper">
<!-- Last name -->
<div class="lname">
{{ form_row(registrationForm.name, {attr:{'class': 'form-control'}})}}
</div>
</div>
</div>
<!-- Address -->
<div class="address">
{{ form_row(registrationForm.adress, {attr:{'class': 'form-control'}}) }}
</div>
<!-- E-mail -->
<div class="email">
{{ form_row(registrationForm.email, {attr:{'class': 'form-control'}}) }}
</div>
<!-- Password -->
<div class="password">
{{ form_row(registrationForm.plainPassword, {attr:{'class': 'form-control'}}) }}
</div><br>
<div class="form-check">
{{ form_row(registrationForm.agreeTerms,{label: 'Accept conditions'}) }}
</div>
<!-- Sign up button -->
<input type="hidden" name="_csrf_token" value="{{ fos_csrf_provider.refreshToken('authenticate') }}"/>
<button class="registration-button" type="submit">Register</button>
<hr>
</a>
</p>
{{ form_end(registrationForm) }}
</form>
和 UserAuthenticator.php
<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
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\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Csrf\CsrfToken;
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
use Symfony\Component\Security\Http\Util\TargetPathTrait;
class UserAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
{
use TargetPathTrait;
public const LOGIN_ROUTE = 'app_login';
private $entityManager;
private $urlGenerator;
private $csrfTokenManager;
private $passwordEncoder;
public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
{
$this->entityManager = $entityManager;
$this->urlGenerator = $urlGenerator;
$this->csrfTokenManager = $csrfTokenManager;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request)
{
return self::LOGIN_ROUTE === $request->attributes->get('_route')
&& $request->isMethod('POST');
}
public function getCredentials(Request $request)
{
$credentials = [
'email' => $request->request->get('email'),
'password' => $request->request->get('password'),
'csrf_token' => $request->request->get('_csrf_token'),
];
$request->getSession()->set(
Security::LAST_USERNAME,
$credentials['email']
);
return $credentials;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$token = new CsrfToken('authenticate', $credentials['csrf_token']);
if (!$this->csrfTokenManager->isTokenValid($token)) {
throw new InvalidCsrfTokenException();
}
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $credentials['email']]);
if (!$user) {
// fail authentication with a custom error
throw new CustomUserMessageAuthenticationException('Can\’t find this email address in the database');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
}
/**
* Used to upgrade (rehash) the user's password automatically over time.
*/
public function getPassword($credentials): ?string
{
return $credentials['password'];
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
{
if ($targetPath = $this->getTargetPath($request->getSession(), $providerKey)) {
return new RedirectResponse($targetPath);
}
return new RedirectResponse($this->urlGenerator->generate('app_home'));
//throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
}
protected function getLoginUrl()
{
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
}
}
带登录模板
<form action="{{ path('app_loginform') }}" method="post" id="formLogin">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
<h1 class="form-signin-heading">Login</h1>
<label for="inputEmail" class="myP">email</label>
<input type="email" name="email" id="inputEmail" class="form-control" required autofocus>
<label for="inputPassword" class="myP">password</label>
<input type="password" name="password" id="inputPassword" class="form-control" required>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
<button class="connexion-button" type="submit">
Connection
</button>
</form>
```