gpt4 book ai didi

authentication - 在安全或自定义提供程序之前加载监听器

转载 作者:行者123 更新时间:2023-12-04 05:11:20 25 4
gpt4 key购买 nike

我正在开发一个与经典用户表单完全相同的自定义提供程序,但是我必须提供第二个参数来识别用户:websiteId(我正在创建一个动态网站平台)。

所以用户名不再是唯一的,而是用户名和网站 ID 的组合。

我成功创建了自定义身份验证,我遇到的最后一个问题是通过监听器从域中获取 websiteId,它可以工作,但不幸的是,在我的身份验证提供程序之后加载了从域中获取网站 ID 的方法,因此我可以没有及时获取网站 ID :(

我尝试更改监听器优先级(测试 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

最佳答案

Firewall::onKernelRequest 以 8 (sf2.2) 的优先级注册。优先级为 9 应确保首先调用您的监听器(对我有用)。

我有一个类似的问题,即在单个 sf2.2 应用程序中创建特定于子域​​的“Campaign”站点: {campaign}.{domain} 。每个用户都有许多事件,我和你一样,想阻止没有给定事件的用户登录。

我的解决方案是创建一个 Doctrine 过滤器,将我的事件条件添加到 {campaign}.{domain} 下的每个相关查询中。 kernel.request 监听器(优先级为 9!)负责在我的通用用户提供程序尝试 loadUserByUsername 之前激活过滤器。我使用 mongodb,但 ORM 的想法是相似的。

最好的部分是我仍在使用股票身份验证类。这基本上就是它的全部内容:

配置文件:

doctrine_mongodb:
document_managers:
default:
filters:
campaign:
class: My\Filter\CampaignFilter
enabled: false

事件过滤器.php:
class CampaignFilter extends BsonFilter
{
public function addFilterCriteria(ClassMetadata $targetMetadata)
{
$class = $targetMetadata->name;
$campaign = $this->parameters['campaign'];
$campaign = $campaign instanceof Campaign ? $campaign->getId() : $campaign;
if ($targetMetadata->hasField('campaign')) {
return array('campaign' => $this->parameters['campaign']);
}
if ($targetMetadata->hasField('campaigns')) {
return array('campaigns' => $this->parameters['campaign']);
}
return array();
}
}

我的听众被声明为:
    <service id="my.campaign_listener" class="My\EventListener\CampaignListener">
<tag name="kernel.event_listener" event="kernel.request" method="onKernelRequest" priority="9" />
<argument type="service" id="doctrine.odm.mongodb.document_manager" />
</service>

监听器类:
class CampaignListener
{
private $dm;

public function __construct(DocumentManager $dm)
{
$this->dm = $dm;
}

public function onKernelRequest(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST != $event->getRequestType()) {
return;
}

$request = $event->getRequest();
if ($campaign = $request->attributes->get('campaign', false)) {
$filters = $this->dm->getFilterCollection();
$filter = $filters->enable('campaign');
$filter->setParameter('campaign', $campaign);
}
}
}

由于我的路由配置,这里的请求中可以使用“campaign”:
campaign:
resource: "@My/Controller/CampaignController.php"
type: annotation
host: "{campaign}.{domain}"
defaults:
campaign: test
domain: %domain%
requirements:
domain: %domain%

.. %domain% 是来自 config.yml 或 config_dev.yml 的参数

关于authentication - 在安全或自定义提供程序之前加载监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14893043/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com