在 Symfony2 中检查具有多个属性的用户登录



>我正在Symfony2中构建一个多租户应用程序。 对于安全的"管理"区域,我有一个自定义实体提供程序(请参阅:http://symfony.com/doc/current/cookbook/security/entity_provider.html(

但是,似乎Symfony2只支持检查单个属性上的实体。

my_entity_provider:
            entity:
                class:              SecurityBundle:User
                property:           email

但是,在我的应用程序中,单个用户可以拥有具有相同电子邮件地址的多个帐户。我需要在登录时检查租户 ID 属性。

my_entity_provider:
            entity:
                class:              SecurityBundle:User
                property:           email, tenantID

我不确定如何在Symfony2中完成此操作。 我已经能够在创建新用户时覆盖 loadUsername 方法,但这并没有被 Symfony2 安全性中的login_check使用(而且它真的很丑陋(。

 public function loadUserByUsername($username)
    {
        /* we create a concatenated string in the  User entity to pass both
        the email and tenantId values as the "username" */
        $user_parts = explode("|", $username); 
        $q = $this->createQueryBuilder('u')
            ->where('u.tenantId = :tenantid AND u.email = :email')
            ->setParameter('tenantID', $user_parts[1])
            ->setParameter('email', $user_parts[0])
            ->getQuery();
        try { 
            $user = $q->getSingleResult();
        } catch (NoResultException $e) {
            throw new UsernameNotFoundException(sprintf('Unable to find an active User object identified by "%s".', $username), null, 0, $e);
        }
        return $user;
    }

有关实现具有多个属性的自定义安全提供程序的任何指导? 谢谢!

您说您使用自定义身份验证提供程序,但我看不到在哪里。我认为您使用默认实体提供程序,该提供程序确实使用关联的实体存储库

如果您在配置中定义了property,它将使用存储库"findOneBy"方法。

否则,如果你定义了一个自定义repositoryClass,并且这个自定义存储库实现了UserPrviderInterface,symfony将调用loadUserByUsername

因此,对于调用 loadUserByUsername 方法的示例,只需从 security.yml 中删除property: email

否则,我想到了许多更清洁的解决方案,但在我看来最好的是

  • 创建自己的用户提供程序

这是一个简单的过程:

  • 创建一个实现用户提供程序接口的类
  • 为该类创建一个服务(例如 ID 为 app.security.user.provider (
  • 配置 Security.yml 以使用此服务

    1. 类:(伪代码,不要忘记添加 use 语句,...

class UserProvider implements UserProviderInterface
{
public function __construct(ManagerRegistry $doctrine, $tenantIdProvider)
{
     $this->doctrine = $doctrine;
     $this->tenantIdProvider = $tenantIdProvider;
}
public function loadUserByUsername($username)
{
    $this->doctrine->getRepository('AppEntityUser')->findOneBy([
        'email' => $username,
        'tenant' => $this->tenantIdProvider->getId(), // HERE $tenantIdProvider can be your listener for example.
    ]);
}
// more methods maybe?
}

  1. 服务(services.yml, app/config/config.yml, ...你想要的地方(

服务业:

app.security.user.provider:
    class: UserProvider
    arguments:
        - '@doctrine'
        - '@app.tenant_id.provider' #maybe?
  1. 安全配置

安全:

providers:
    user:
        id: app.security.user.provider
我认为在你的

用户存储库中覆盖loadUserByUsername 就像你一样,在你的情况下是一件好事。

也许您的问题出在配置中:

使用属性"属性",symfony不使用你自己的loadUserByUsername

因此,只需删除"属性"行,我希望一切正常:

my_entity_provider:
    entity:
        class: SecurityBundle:User

你见过我假设的自定义身份验证吗? http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html#the-listener

忽略这是针对 WSSE 的,这将允许你创建自己的自定义句柄,使用租户 ID 和电子邮件地址手动进行身份验证

最新更新