我正在开发一个与经典用户表单完全一样的自定义提供程序,但是我必须提供第二个参数来识别用户:websiteId(我正在创建一个动态网站平台)。
因此,用户名不再是唯一的,而是用户名和 websiteId 的组合。
我成功创建了自定义身份验证,我遇到的最后一个问题是通过侦听器从域中获取 websiteId,它可以工作,但幸运的是,从域获取网站 id 的方法是在我的身份验证提供程序之后加载的,所以我可以'没有及时得到 websiteId :(
我试图更改侦听器优先级(测试 9999、1024、255 和 0,以及负数 -9999、-1024、-255 等......),但徒劳无功,它总是在之后加载。
这是我的代码:
服务.yml:
services:
# Listeners _________________
website_listener:
class: Sybio\Bundle\WebsiteBundle\Services\Listener\WebsiteListener
arguments:
- @doctrine
- @sybio.website_manager
- @translator
- %sybio.states%
tags:
- { name: kernel.event_listener, event: kernel.request, method: onDomainParse, priority: 255 }
# Security _________________
sybio_website.user_provider:
class: Sybio\Bundle\WebsiteBundle\Security\Authentication\Provider\WebsiteUserProvider
arguments: [@website_listener, @doctrine.orm.entity_manager]
我的听众是“website_listener”,你可以看到我将它用于我的 sybio_website.user_provider 作为参数。
网站监听器:
// ...
class WebsiteListener extends Controller
{
protected $doctrine;
protected $websiteManager;
protected $translator;
protected $websiteId;
/**
* @var array
*/
protected $entityStates;
public function __construct($doctrine, $websiteManager, $translator, $entityStates)
{
$this->doctrine = $doctrine;
$this->websiteManager = $websiteManager;
$this->translator = $translator;
$this->entityStates = $entityStates;
}
/**
* @param Event $event
*/
public function onDomainParse(Event $event)
{
$request = $event->getRequest();
$website = $this->websiteManager->findOne(array(
'domain' => $request->getHost(),
'state' => $this->entityStates['website']['activated'],
));
if (!$website) {
throw $this->createNotFoundException($this->translator->trans('page.not.found'));
}
$this->websiteId = $website->getId();
}
/**
* @param integer $websiteId
*/
public function getWebsiteId()
{
return $this->websiteId;
}
}
$websiteId 是水合的,不像你在我的提供者中看到的那样及时......
网站用户提供者:
<?php
namespace Sybio\Bundle\WebsiteBundle\Security\Authentication\Provider;
// ...
class WebsiteUserProvider implements UserProviderInterface
{
private $em;
private $websiteId;
private $userEntity;
public function __construct($websiteListener, EntityManager $em)
{
$this->em = $em;
$this->websiteId = $websiteListener->getWebsiteId(); // Try to get the website id from my listener, but it's method onDomainParse is not called in time
$this->userEntity = 'Sybio\Bundle\CoreBundle\Entity\User';
}
public function loadUserByUsername($username)
{
// I need the websiteId here to identify the user by its username and the website:
if ($user = $this->findUserBy(array('username' => $username, 'website' => $this->websiteId))) {
return $user;
}
throw new UsernameNotFoundException(sprintf('No record found for user %s', $username));
}
// ...
}
所以任何想法都会很感激;)我花了很多时间来设置我的身份验证配置,但现在我无法及时获得 websiteId,太糟糕了:(
谢谢你的回答!
编辑:
我还需要了解我的身份验证系统的其他文件,我认为我无法在加载时控制提供程序的位置,因为它们在 security.yml 配置中是有的:
网站身份验证提供者:
// ...
class WebsiteAuthenticationProvider extends UserAuthenticationProvider
{
private $encoderFactory;
private $userProvider;
/**
* @param \Symfony\Component\Security\Core\User\UserProviderInterface $userProvider
* @param UserCheckerInterface $userChecker
* @param $providerKey
* @param EncoderFactoryInterface $encoderFactory
* @param bool $hideUserNotFoundExceptions
*/
public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, $providerKey, EncoderFactoryInterface $encoderFactory, $hideUserNotFoundExceptions = true)
{
parent::__construct($userChecker, $providerKey, $hideUserNotFoundExceptions);
$this->encoderFactory = $encoderFactory;
$this->userProvider = $userProvider;
}
/**
* {@inheritdoc}
*/
protected function retrieveUser($username, UsernamePasswordToken $token)
{
$user = $token->getUser();
if ($user instanceof UserInterface) {
return $user;
}
try {
$user = $this->userProvider->loadUserByUsername($username);
if (!$user instanceof UserInterface) {
throw new AuthenticationServiceException('The user provider must return a UserInterface object.');
}
return $user;
} catch (UsernameNotFoundException $notFound) {
throw $notFound;
} catch (\Exception $repositoryProblem) {
throw new AuthenticationServiceException($repositoryProblem->getMessage(), $token, 0, $repositoryProblem);
}
}
// ...
}
工厂:
// ...
class WebsiteFactory extends FormLoginFactory
{
public function getKey()
{
return 'website_form_login';
}
protected function getListenerId()
{
return 'security.authentication.listener.form';
}
protected function createAuthProvider(ContainerBuilder $container, $id, $config, $userProviderId)
{
$provider = 'security.authentication_provider.sybio_website.'.$id;
$container
->setDefinition($provider, new DefinitionDecorator('security.authentication_provider.sybio_website'))
->replaceArgument(0, new Reference($userProviderId))
->replaceArgument(2, $id)
;
return $provider;
}
}
SybioWebsiteBundle(依赖):
// ...
class SybioWebsiteBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$extension = $container->getExtension('security');
$extension->addSecurityListenerFactory(new WebsiteFactory());
}
}
安全:
security:
firewalls:
main:
provider: website_provider
pattern: ^/
anonymous: ~
website_form_login:
login_path: /login.html
check_path: /login
logout:
path: /logout.html
target: /
providers:
website_provider:
id: sybio_website.user_provider