Symfony 4自定义用户提供者从数据库取用户返回“Bad Credentials”
看起来你的问题核心出在Doctrine DQL查询的实体引用错误,导致无法从数据库获取用户数据,最终触发UsernameNotFoundException,进而返回"Bad credentials"错误。咱们一步步来排查修复:
1. 修正DQL查询的实体类引用
你当前的查询用了数据库表名users,但Doctrine的DQL要求使用实体类的完全限定类名(FQCN),而非数据库表名。比如如果你的用户实体是App\Entity\User,查询需要改成:
$userData = $this->doctrine->getManager() ->createQueryBuilder('SELECT u FROM App\Entity\User u WHERE u.email = :email') ->setParameter('email', $email) ->getQuery() ->getOneOrNullResult();
小提示:可以查看你的用户实体类上的
@ORM\Table注解确认映射关系,比如实体类里如果有@ORM\Table(name="users"),说明这个实体对应数据库的users表,但DQL查询必须用实体类名,不能直接用表名。
2. 修复UsernameNotFoundException的变量未定义问题
当$userData不存在时,你抛出异常用了$username变量,但这个变量只有在$userData存在时才会赋值,会导致未定义变量错误。应该直接用传入的$email:
throw new UsernameNotFoundException( sprintf('Username "%s" does not exist.', $email) );
3. 调试查询结果的小技巧
如果修正查询后还是没返回数据,可以打印生成的SQL语句来排查问题:
$query = $this->doctrine->getManager() ->createQueryBuilder('SELECT u FROM App\Entity\User u WHERE u.email = :email') ->setParameter('email', $email) ->getQuery(); // 打印生成的SQL,方便验证是否正确 var_dump($query->getSQL()); $userData = $query->getOneOrNullResult(); var_dump($userData); exit;
这样能直观看到SQL是否符合预期,参数是否正确绑定。
4. 检查WebserviceUser类的实现
确保你的WebserviceUser类正确实现了Symfony\Component\Security\Core\User\UserInterface,特别是getUsername()、getPassword()、getRoles()这些核心方法,它们是Security组件验证身份的关键。
一个基础的WebserviceUser实现示例:
<?php // src/Security/User/WebserviceUser.php namespace App\Security\User; use Symfony\Component\Security\Core\User\UserInterface; class WebserviceUser implements UserInterface { private $email; private $password; private $salt; private $roles; public function __construct(string $email, string $password, ?string $salt, array $roles) { $this->email = $email; $this->password = $password; $this->salt = $salt; $this->roles = $roles; } public function getUsername(): string { // 如果用邮箱作为用户名,直接返回email即可 return $this->email; } public function getPassword(): string { return $this->password; } public function getSalt(): ?string { return $this->salt; } public function getRoles(): array { return $this->roles; } public function eraseCredentials() { // 可选:清空敏感临时数据 } }
总结
最关键的问题是DQL查询误用了数据库表名而非实体类名,导致无法获取用户数据。修正这个问题后,再检查异常变量、实体类实现这些细节,应该就能解决"Bad credentials"的错误了。
内容的提问来源于stack exchange,提问作者user3684098

