[Symfony6 系列] 身份认证

Symfony 身份认证流程及事件

安装包列表

#创建空命令,控制器,表单类,安全类、测试等等
composer require --dev symfony/maker-bundle 
#调试程序
composer require --dev symfony/profiler-pack
composer require symfonycasts/verify-email-bundle
composer require jms/serializer-bundle
#接口文档工具
composer require nelmio/api-doc-bundle
#NelmioApiDocBundle 依赖模板
composer require symfony/twig-bundle
composer require symfony/asset

创建用户 Entity

php bin/console 1make:user User
#更新数据库
php bin/console doctrine:schema:update --force

使用username作为唯一标识,邮箱和手机号作为补充字段,也可以作为登录认证字段。

在 App\Entity\User.php 增加字段

#[ORM\Column(type: 'datetime',nullable: true, options: [
	"comment" => "最后一次登录日期"
])]
private ?\DateTime $lastLogin = null;

/**
 * 邮箱不允许重复,通过逻辑验证重复
*/
#[ORM\Column( length: 30, unique: false, nullable: true )]
private ?string $email = null;

/**
 * 手机号码不允许重复,通过逻辑验证重复
 */
#[ORM\Column(
	length: 20,
	unique: false,
	nullable: true,
	options: [
  	"comment" => "手机号"
	]
)]
  private ?string $phone = null;

设置Provider

security.yaml 设置自定义的数据对象 provider

security:
    providers:
		# used to reload user from session & other features (e.g. switch_user)
        app_user_provider:
            entity:
                class: App\Entity\User
                property: username

创建表单身份认证器

php bin/console make:auth

自动创建登录表单控制器,便于调试。

App\Security\FormUserAuthenticator

namespace App\Security;

use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Util\TargetPathTrait;

/**
 * 表单类型身份认证器
 */
class FormUserAuthenticator extends AbstractLoginFormAuthenticator
{
    use TargetPathTrait;

    public const LOGIN_ROUTE = 'app_login';

    public function __construct(private UrlGeneratorInterface $urlGenerator)
    {
    }

    public function authenticate(Request $request): Passport
    {
        $username = $request->request->get('username', '');

        $request->getSession()->set(Security::LAST_USERNAME, $username);

        return new Passport(
            new UserBadge($username),
            new PasswordCredentials($request->request->get('password', '')),
            [
                new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')),
            ]
        );
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
            return new RedirectResponse($targetPath);
        }

        // For example:
         return new RedirectResponse($this->urlGenerator->generate('homepage'));
//        throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
    }


    protected function getLoginUrl(Request $request): string
    {
        return $this->urlGenerator->generate(self::LOGIN_ROUTE);
    }
}

LexikJWT 配置

security:
	 firewalls:
        api_login:
            pattern: ^/api/login
            stateless: true
            provider: app_user_provider
            json_login:
                username_path: username
                password_path: password
                check_path: /api/login_check
                success_handler: lexik_jwt_authentication.handler.authentication_success
                failure_handler: lexik_jwt_authentication.handler.authentication_failure
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        api:
            pattern: ^/api
            stateless: true
            provider: app_user_provider
            jwt: ~
        main:
            lazy: true
            custom_authenticator: App\Security\FormUserAuthenticator
            logout:
                path: app_logout
            provider: app_user_provider
	access_control:
        - { path: ^/api/login, roles: PUBLIC_ACCESS }
        - { path: ^/api,       roles: IS_AUTHENTICATED_FULLY }

基于表单的登录认证

https://symfony62.localhost:44310/login

基于JWT的登录认证

https://symfony62.localhost:44310/api/login_check

参考文章

[1]  https://symfony.com/doc/current/security/custom_authenticator.html 自定义身份验证器

[2]  https://symfony.com/bundles/LexikJWTAuthenticationBundle/current/index.html LexikJWTAuthentication安装文档

[3]  https://symfony.com/doc/current/security.html#the-user 基于数据库的用户

[4]  https://symfony.com/bundles/SymfonyMakerBundle/current/index.html MakerBundle

[5]  https://symfony.com/doc/5.2/security/form_login_setup.html#generating-the-login-form 创建表单身份认证器及登录页

  1. ↩︎

发表评论