如何在Symfony 4.3中实现自己的用户身份验证系统(第3部分(创建登录表单和注销路径))

本文概述

  • 1.创建登录路径
  • 2.创建登录表单身份验证器
  • 3.注册Guard Authenticator
  • 4.创建登录视图
  • 5.访问和登录
  • 6.创建注销路径
  • 7.启用注销
在上一篇文章中, 我们向你展示了如何创建注册表单以在应用程序中添加新用户。显然, 如果用户已经在你的应用程序上拥有一个帐户, 则他们需要登录到该应用程序, 因此他在访问你的网站时将拥有一个会话和凭据。
Symfony 4非常容易实现, 我们将在短期内向你说明如何创建登录和注销路径:
1.创建登录路径 【如何在Symfony 4.3中实现自己的用户身份验证系统(第3部分(创建登录表单和注销路径))】最初, 我们需要创建一条路径, 用户可以在其中访问登录表单。在应用程序的控制器目录(/ src / Controller /)中创建具有以下内容的SecurityController.php文件:
< ?php// src/Controller/SecurityController.phpnamespace 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("/login", name="app_login")*/public function login(AuthenticationUtils $authenticationUtils): Response{// Get the login error if there is one$error = $authenticationUtils-> getLastAuthenticationError(); // Retrive the last email entered by the user$lastUsername = $authenticationUtils-> getLastUsername(); return $this-> render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]); }}

通过依赖项注入, AuthenticationUtils实例将通过登录对象作为第一个参数接收该对象, 你可以从该对象中获取示例信息, 最后的身份验证错误以及表单上提供的用户名。
2.创建登录表单身份验证器 接下来, 你将需要创建扩展了AbstractFormLoginAuthenticator基类的authenticator类, 这将使表单登录身份验证更加容易。此类将在构造函数中接收此模块所需的4个关键组件, 即实体管理器(用于创建查询), 路由器接口(用于创建路由), CSRF令牌管理器(检查表单是否有效)和密码编码器(以检查身份验证是否有效)。
当supports方法返回true时, 将执行此身份验证器(在步骤3中注册后)。在这种情况下, 当当前路由为app_login且方法为POST(提交表单时)时, 它将被触发:
< ?php// src/Security/LoginFormAuthenticator.phpnamespace App\Security; use App\Entity\User; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\RouterInterface; 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\Http\Util\TargetPathTrait; class LoginFormAuthenticator extends AbstractFormLoginAuthenticator{use TargetPathTrait; private $entityManager; private $router; private $csrfTokenManager; private $passwordEncoder; public function __construct(EntityManagerInterface $entityManager, RouterInterface $router, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder){$this-> entityManager = $entityManager; $this-> router = $router; $this-> csrfTokenManager = $csrfTokenManager; $this-> passwordEncoder = $passwordEncoder; }public function supports(Request $request){return 'app_login' === $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 errorthrow new CustomUserMessageAuthenticationException('Email could not be found.'); }return $user; }public function checkCredentials($credentials, UserInterface $user){return $this-> passwordEncoder-> isPasswordValid($user, $credentials['password']); }public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey){if ($targetPath = $this-> getTargetPath($request-> getSession(), $providerKey)) {return new RedirectResponse($targetPath); }// For example : return new RedirectResponse($this-> router-> generate('some_route')); throw new \Exception('TODO: provide a valid redirect inside '.__FILE__); }protected function getLoginUrl(){return $this-> router-> generate('app_login'); }}

请注意, 你需要在此类中处理, 特别是在onAuthenticationSuccess回调上, 现在用户会发生什么。通常, 你应该将他重定向到应用程序的索引页面或其他内容, 因此请确保根据你的需要修改回调的代码, 例如, 不要引发异常, 而只需重定向到我们的索引路由即可:
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey){if ($targetPath = $this-> getTargetPath($request-> getSession(), $providerKey)) {return new RedirectResponse($targetPath); }//Redirect user to homepagereturn new RedirectResponse($this-> router-> generate('app_index')); }

3.注册Guard Authenticator 身份验证器已经存在, 但是你需要在主防火墙中注册它:
# app/config/packages/security.yamlsecurity:firewalls:main:anonymous: trueguard:authenticators:- App\Security\LoginFormAuthenticator# Easy way to control access for large sections of your site# Note: Only the *first* access control that matches will be usedaccess_control:- { path: ^/login$, roles: IS_AUTHENTICATED_ANONYMOUSLY }

这样做, 该类将被注册, 并在该类的supports方法返回true时作出反应。
4.创建登录视图 最后但同样重要的是, 在登录路径中, 我们呈现了一个Twig视图, 即login.html.twig, 尚未创建, 并将包含以下标记(存储在/ app / templates / security /中):
{# /app/templates/security/login.html.twig #}{% extends 'base.html.twig' %}{% block title %}Log in!{% endblock %}{% block body %}< form method="post"> {# If there's any error, display it to the user #}{% if error %}< div class="alert alert-danger"> {{ error.messageKey|trans(error.messageData, 'security') }}< /div> {% endif %}< h1> Please sign in< /h1> {# Email Input #}< label for="inputEmail" class="sr-only"> Email< /label> < input type="email" value="http://www.srcmini.com/{{ last_username }}" name="email" id="inputEmail" class="form-control" placeholder="Email" required autofocus> {# Password Input #}< label for="inputPassword" class="sr-only"> Password< /label> < input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password" required> {# CSRF Token Input #}< input type="hidden" name="_csrf_token" value="http://www.srcmini.com/{{ csrf_token('authenticate') }}" /> < button class="btn btn-lg btn-primary" type="submit"> Sign in< /button> < /form> {% endblock %}

5.访问和登录 创建视图后, 如果你尝试访问路线mywebsite.com/login, 则会看到登录表单:
如何在Symfony 4.3中实现自己的用户身份验证系统(第3部分(创建登录表单和注销路径))

文章图片
提供通过本文第2部分中创建的注册表单注册的用户的一些凭据。如果你在其中指定了重定向路由, 则所有操作都会正常进行, 并且你将被重定向到该路由, 并且你会在开发工具中看到已通过身份验证的信息:
如何在Symfony 4.3中实现自己的用户身份验证系统(第3部分(创建登录表单和注销路径)) 这就是登录部分!
6.创建注销路径 现在, 你的用户如果登录也应该能够关闭会话, 因此你需要公开注销路径。你可以在还创建了登录路由的同一SecurityController中创建它, 因此可以添加它, 这是一个简单的空操作, 名为logout:
< ?php// src/Controller/SecurityController.phpnamespace 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("/logout", name="app_logout")*/public function logout(): Response{// controller can be blank: it will never be executed!}}

请注意, 该路由将具有在下一步中使用的标识符, 以启用身份验证系统的注销功能。
7.启用注销 现在已经存在注销路由, 你需要在security.yaml文件的主防火墙中指定它:
# app/config/packages/security.yamlsecurity:firewalls:main:logout:path: app_logout# where to redirect after logout ?? You can specify the target property# target: app_any_route

你还可以在此块中指定注销后将用户重定向到的位置。注册此路由后, 登录后访问路由mywebsite.com/logout, 该会话将被删除, 用户将需要再次登录该应用程序。
阅读教程的所有部分” 如何在SYMFONY 4.3中实施你自己的用户认证系统”
  • 第1部分:创建自定义用户类。
  • 第2部分:创建用户注册表单。
  • 第3部分:创建登录表单和注销路径。
对本教程的兴趣链接
  • https://symfony.com/doc/current/security.html
编码愉快!

    推荐阅读