我正在Symfony2中构建一个多租户应用程序。对于安全的“admin”区域,我有一个自定义实体提供程序(请参阅: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;
}
有关实施具有多个属性的自定义安全提供程序的任何指导?谢谢!
答案 0 :(得分:6)
您说您使用自定义身份验证提供程序,但我没有看到。 我认为您使用的是默认实体提供程序,它确实使用关联的实体 Repositiory 。
如果在配置中定义了property
,它将使用存储库``findOneBy`方法。
否则,如果您定义了自定义repositoryClass
,并且此自定义资源库实现了UserPrviderInterface,则symfony will call loadUserByUsername
因此,对于您调用loadUserByUsername方法的示例,只需从security.yml中删除property: email
否则,我会想到许多更清洁的解决方案,但我最关心的是
这是一个简单的过程:
app.security.user.provider
)配置security.yml以使用此服务
class UserProvider implements UserProviderInterface
{
public function __construct(ManagerRegistry $doctrine, $tenantIdProvider)
{
$this->doctrine = $doctrine;
$this->tenantIdProvider = $tenantIdProvider;
}
public function loadUserByUsername($username)
{
$this->doctrine->getRepository('App\Entity\User')->findOneBy([
'email' => $username,
'tenant' => $this->tenantIdProvider->getId(), // HERE $tenantIdProvider can be your listener for example.
]);
}
// more methods maybe?
}
服务:
app.security.user.provider:
class: UserProvider
arguments:
- '@doctrine'
- '@app.tenant_id.provider' #maybe?
安全性:
providers:
user:
id: app.security.user.provider
答案 1 :(得分:2)
我认为在你的UserRepository中覆盖loadUserByUsername就像你一样,在你的情况下是好事。
也许您的问题出在配置中:
使用属性“property”,symfony不使用您自己的loadUserByUsername
所以,只需删除“属性”行,我希望一切正常:
my_entity_provider:
entity:
class: SecurityBundle:User
答案 2 :(得分:1)
你见过我认为的自定义身份验证吗? http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html#the-listener
忽略这是针对WSSE的,这将允许您创建自己的自定义句柄,使用手动身份验证的租户ID和电子邮件地址