如何确保 Symfony UserBadge 始终接受不区分大小写的用户名?

How to make sure case insensitive usernames are always accepted by Symfony UserBadge?

我在我的 Symfony 5 项目中创建了一个自定义 AbstractAuthenticator subclass,它可以处理 HTTP headers.

中包含的用户凭据
public function authenticate(Request $request): PassportInterface {
    $userIdentifier = $this->getUserIdentifierFromRequest();
    
    return new Passport(
        new UserBadge($this->userIdentifier),
        new CustomCredentials(
            function ($credentials, UserInterface $user) {
                ...
            },
            
            $credentialFromRequest
        )
    );
}

这工作正常,当检查到无效的用户名时,UserBadge 抛出 UserNotFoundException

但是,我想知道为什么这个实现对给定的用户名不区分大小写

我检查了 Symfony 代码,UserBadge 使用 EntityUserProvider class 执行简单的 $repository->findOneBy([$this->property => $identifier])(在我的例子中按字段 email 查找) .经过一些搜索,我找到了相关的答案,这表明 find... 是否区分大小写或不区分大小写很可能取决于底层数据库(在我的例子中是 MariaDB 10)。

有什么方法可以控制用户名查找是否区分大小写?

虽然不区分大小写的搜索在当前项目中很好,但我想确保它保持这种方式,无论我是否将项目移植到具有另一个底层数据库的另一台机器...

您可以创建 a custom User Provider.

然后在您的提供商中,只需在标识符上调用 strtolower(),在标识符列上调用 LOWER()

一个相当简单的实现,假设您在用户提供程序上注入实体管理器。


public function loadUserByIdentifier(string $identifier): UserInterface
{
    $user = $this->em->createQueryBuilder()
            ->select('u')
            ->from(YourUser::class, 'u')
            ->where('LOWER(u.username) = :username')
            ->setParameter('username', strtolower($identifier))
            ->setMaxResults(1)
            ->getQuery()
            ->getOneOrNullResult();

    if (!$user instanceof YourUser::class) {
        throw new UserNotFoundException('No user found for ' . $username);
    }

    return $user;

}

根据您的应用程序限制进行调整。您或许可以将查询本身移动到特定的实体存储库,并在那里创建查询,而不是提供程序。