Symfony 4:已登录状态下删除自身账号的最佳实践
解决删除当前登录用户时的EntityUserProvider标识符错误
这个问题我之前也遇到过,核心原因是Security组件在你删除当前登录用户后,仍然尝试刷新会话中的用户实体,但此时该实体已经失去了数据库标识符,而EntityUserProvider要求用户对象必须携带可映射的标识符才能完成刷新操作。
结论:需要正确配置User类的序列化,同时配合会话清理
1. 确保User类正确序列化标识符字段
Symfony的Security组件依赖会话中序列化的用户对象来刷新用户状态,所以你的User类必须保证标识符(比如id)被正确序列化。
你可以通过两种方式实现:
方式一:实现Serializable接口
use Symfony\Component\Security\Core\User\UserInterface; use Serializable; class User implements UserInterface, Serializable { private ?int $id = null; // 其他属性:username, password等 // ... 实现UserInterface的必要方法(getRoles(), getUserIdentifier()等) public function serialize(): string { // 必须包含id,这是Doctrine映射的核心标识符 return serialize([ $this->id, $this->username, $this->password, ]); } public function unserialize(string $data): void { list( $this->id, $this->username, $this->password, ) = unserialize($data, ['allowed_classes' => true]); } }
方式二:使用Symfony序列化注解(推荐)
如果你的项目使用Symfony Serializer组件,可以用#[SerializableField]注解明确指定需要序列化的字段:
use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Serializer\Annotation\SerializableField; class User implements UserInterface { #[SerializableField] private ?int $id = null; #[SerializableField] private string $username; #[SerializableField] private string $password; // ... 实现UserInterface的必要方法 }
2. 删除用户后立即销毁会话(关键步骤)
光序列化还不够,因为删除当前用户后,会话中仍然存在旧的用户对象,Security组件会在后续请求尝试刷新它。所以在deleteUser方法中,删除用户后必须立即销毁会话:
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\User\UserInterface; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; public function deleteUser( Request $request, UserInterface $currentUser, EntityManagerInterface $em, TokenStorageInterface $tokenStorage ) { // 验证要删除的是当前登录用户(根据你的业务逻辑调整) // $userToDelete = ... 获取要删除的用户实例 $em->remove($currentUser); $em->flush(); // 销毁当前会话,阻止Security后续刷新已删除的用户 $request->getSession()->invalidate(); // 清除Security令牌,彻底移除当前用户的认证状态 $tokenStorage->setToken(null); // 重定向到非认证页面,比如首页或注册页 return $this->redirectToRoute('home'); }
为什么删除其他用户没问题?
当你删除未登录的其他用户时,当前会话的用户实体是你自己的账号,这个实体仍然存在于数据库中,Security组件刷新的是这个有效实体,所以不会触发标识符缺失的错误。而删除自己时,会话中的用户实体对应的数据库记录已被删除,Security尝试刷新时就会报错。
内容的提问来源于stack exchange,提问作者blakyris
相关产品推荐
相关产品推荐

