Symfony 5.4升级后登录更新lastLogin触发username非空约束错误
问题:Symfony升级5.4后FOSUserBundle更新lastLogin时出现字段非空错误
我使用FOSUserBundle进行身份验证,登录成功获取访问令牌后,同一请求中触发安全事件更新用户表lastLogin字段时,抛出SQL错误:Integrity constraint violation: 1048 Column 'username' cannot be null。该问题是将Symfony从4.3版本升级到5.4版本后出现的。
Security配置文件
security: password_hashers: FOS\UserBundle\Model\UserInterface: algorithm: auto cost: 13 providers: fos_userbundle: id: fos_user.user_provider.username firewalls: main: pattern: ^/ user_checker: security.user_checker form_login: provider: fos_userbundle csrf_token_generator: security.csrf.token_manager logout: true anonymous: true remember_me: secret: '%kernel.secret%' lifetime: 604800 # 1 week in seconds path: / access_control: - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: '%env(X-FORWARDED-PROTO)' } ...... imports: - { resource: 'role_hierarchy.yaml' }
已安装的Composer依赖
{ "doctrine/doctrine-bundle": "2.7.2", "doctrine/doctrine-migrations-bundle": "3.2.4", "doctrine/orm": "2.15.3", "friendsofsymfony/user-bundle": "3.2.1" }
问题原因及解决方法
1. 核心原因
Symfony 5.4调整了安全事件的生命周期和用户对象的序列化逻辑,而FOSUserBundle 3.2.1与该版本的兼容性不足,导致更新lastLogin时用户对象的username字段被意外置空。
2. 具体解决步骤
(1)替换用户提供者
将security配置中的用户提供者从fos_user.user_provider.username改为fos_user.user_provider.username_email,该提供者在处理用户对象时更稳定,可避免字段丢失:
providers: fos_userbundle: id: fos_user.user_provider.username_email
(2)升级FOSUserBundle版本
FOSUserBundle 3.2.1对Symfony 5.4的支持不完善,建议升级到3.3.0及以上的稳定版,修复兼容性问题:
composer require friendsofsymfony/user-bundle:^3.3
(3)检查用户实体映射
确认你的用户实体中username字段的Doctrine映射未被错误设置为允许空值,同时验证实体类的getUsername()/setUsername()方法逻辑正常,无值丢失情况。
(4)手动处理lastLogin更新(备选方案)
如果上述方法无效,可在登录成功事件中手动更新lastLogin,绕过FOSUserBundle的自动处理:
// src/EventListener/LoginSuccessListener.php namespace App\EventListener; use FOS\UserBundle\Model\UserManagerInterface; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; class LoginSuccessListener { private $userManager; public function __construct(UserManagerInterface $userManager) { $this->userManager = $userManager; } public function onInteractiveLogin(InteractiveLoginEvent $event) { $user = $event->getAuthenticationToken()->getUser(); if ($user instanceof \FOS\UserBundle\Model\UserInterface) { $user->setLastLogin(new \DateTime()); $this->userManager->updateUser($user); } } }
在services.yaml中注册监听:
App\EventListener\LoginSuccessListener: tags: - { name: kernel.event_listener, event: security.interactive_login }
内容的提问来源于stack exchange,提问作者kenan ismail
相关产品推荐
相关产品推荐

