Added remember me functionality
This commit is contained in:
parent
1c810d5d2a
commit
ddf430fc1e
@ -42,7 +42,7 @@ class AnonymousFactory implements SecurityFactoryInterface, AuthenticatorFactory
|
||||
return [$providerId, $listenerId, $defaultEntryPoint];
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, ?string $userProviderId): string
|
||||
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
|
||||
{
|
||||
if (null === $config['secret']) {
|
||||
$config['secret'] = new Parameter('container.build_hash');
|
||||
|
@ -25,5 +25,5 @@ interface AuthenticatorFactoryInterface
|
||||
*
|
||||
* @return string|string[] The authenticator service ID(s) to be used by the firewall
|
||||
*/
|
||||
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, ?string $userProviderId);
|
||||
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, string $userProviderId);
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ class FormLoginFactory extends AbstractFactory implements AuthenticatorFactoryIn
|
||||
return $entryPointId;
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, ?string $userProviderId): string
|
||||
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
|
||||
{
|
||||
$authenticatorId = 'security.authenticator.form_login.'.$id;
|
||||
$defaultOptions = array_merge($this->defaultSuccessHandlerOptions, $this->options);
|
||||
|
@ -46,7 +46,7 @@ class HttpBasicFactory implements SecurityFactoryInterface, AuthenticatorFactory
|
||||
return [$provider, $listenerId, $entryPointId];
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, ?string $userProviderId): string
|
||||
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
|
||||
{
|
||||
$authenticatorId = 'security.authenticator.http_basic.'.$id;
|
||||
$container
|
||||
|
@ -20,7 +20,7 @@ use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpFoundation\Cookie;
|
||||
use Symfony\Component\Security\Http\EventListener\RememberMeLogoutListener;
|
||||
|
||||
class RememberMeFactory implements SecurityFactoryInterface
|
||||
class RememberMeFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface
|
||||
{
|
||||
protected $options = [
|
||||
'name' => 'REMEMBERME',
|
||||
@ -46,29 +46,8 @@ class RememberMeFactory implements SecurityFactoryInterface
|
||||
;
|
||||
|
||||
// remember me services
|
||||
if (isset($config['service'])) {
|
||||
$templateId = $config['service'];
|
||||
$rememberMeServicesId = $templateId.'.'.$id;
|
||||
} elseif (isset($config['token_provider'])) {
|
||||
$templateId = 'security.authentication.rememberme.services.persistent';
|
||||
$rememberMeServicesId = $templateId.'.'.$id;
|
||||
} else {
|
||||
$templateId = 'security.authentication.rememberme.services.simplehash';
|
||||
$rememberMeServicesId = $templateId.'.'.$id;
|
||||
}
|
||||
|
||||
$rememberMeServices = $container->setDefinition($rememberMeServicesId, new ChildDefinition($templateId));
|
||||
$rememberMeServices->replaceArgument(1, $config['secret']);
|
||||
$rememberMeServices->replaceArgument(2, $id);
|
||||
|
||||
if (isset($config['token_provider'])) {
|
||||
$rememberMeServices->addMethodCall('setTokenProvider', [
|
||||
new Reference($config['token_provider']),
|
||||
]);
|
||||
}
|
||||
|
||||
// remember-me options
|
||||
$rememberMeServices->replaceArgument(3, array_intersect_key($config, $this->options));
|
||||
$templateId = $this->generateRememberMeServicesTemplateId($config, $id);
|
||||
$rememberMeServicesId = $templateId.'.'.$id;
|
||||
|
||||
// attach to remember-me aware listeners
|
||||
$userProviders = [];
|
||||
@ -93,17 +72,8 @@ class RememberMeFactory implements SecurityFactoryInterface
|
||||
;
|
||||
}
|
||||
}
|
||||
if ($config['user_providers']) {
|
||||
$userProviders = [];
|
||||
foreach ($config['user_providers'] as $providerName) {
|
||||
$userProviders[] = new Reference('security.user.provider.concrete.'.$providerName);
|
||||
}
|
||||
}
|
||||
if (0 === \count($userProviders)) {
|
||||
throw new \RuntimeException('You must configure at least one remember-me aware listener (such as form-login) for each firewall that has remember-me enabled.');
|
||||
}
|
||||
|
||||
$rememberMeServices->replaceArgument(0, new IteratorArgument(array_unique($userProviders)));
|
||||
$this->createRememberMeServices($container, $id, $templateId, $userProviders, $config);
|
||||
|
||||
// remember-me listener
|
||||
$listenerId = 'security.authentication.listener.rememberme.'.$id;
|
||||
@ -119,6 +89,42 @@ class RememberMeFactory implements SecurityFactoryInterface
|
||||
return [$authProviderId, $listenerId, $defaultEntryPoint];
|
||||
}
|
||||
|
||||
public function createAuthenticator(ContainerBuilder $container, string $id, array $config, string $userProviderId): string
|
||||
{
|
||||
$templateId = $this->generateRememberMeServicesTemplateId($config, $id);
|
||||
$rememberMeServicesId = $templateId.'.'.$id;
|
||||
|
||||
// create remember me services (which manage the remember me cookies)
|
||||
$this->createRememberMeServices($container, $id, $templateId, [new Reference($userProviderId)], $config);
|
||||
|
||||
// create remember me listener (which executes the remember me services for other authenticators and logout)
|
||||
$this->createRememberMeListener($container, $id, $rememberMeServicesId);
|
||||
|
||||
// create remember me authenticator (which re-authenticates the user based on the remember me cookie)
|
||||
$authenticatorId = 'security.authenticator.remember_me.'.$id;
|
||||
$container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.remember_me'))
|
||||
->replaceArgument(0, new Reference($rememberMeServicesId))
|
||||
->replaceArgument(3, array_intersect_key($config, $this->options))
|
||||
;
|
||||
|
||||
foreach ($container->findTaggedServiceIds('security.remember_me_aware') as $serviceId => $attributes) {
|
||||
// register ContextListener
|
||||
if ('security.context_listener' === substr($serviceId, 0, 25)) {
|
||||
$container
|
||||
->getDefinition($serviceId)
|
||||
->addMethodCall('setRememberMeServices', [new Reference($rememberMeServicesId)])
|
||||
;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new \LogicException(sprintf('Symfony Authenticator Security dropped support for the "security.remember_me_aware" tag, service "%s" will no longer work as expected.', $serviceId));
|
||||
}
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
|
||||
public function getPosition()
|
||||
{
|
||||
return 'remember_me';
|
||||
@ -163,4 +169,63 @@ class RememberMeFactory implements SecurityFactoryInterface
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function generateRememberMeServicesTemplateId(array $config, string $id): string
|
||||
{
|
||||
if (isset($config['service'])) {
|
||||
return $config['service'];
|
||||
}
|
||||
|
||||
if (isset($config['token_provider'])) {
|
||||
return 'security.authentication.rememberme.services.persistent';
|
||||
}
|
||||
|
||||
return 'security.authentication.rememberme.services.simplehash';
|
||||
}
|
||||
|
||||
private function createRememberMeServices(ContainerBuilder $container, string $id, string $templateId, array $userProviders, array $config): void
|
||||
{
|
||||
$rememberMeServicesId = $templateId.'.'.$id;
|
||||
|
||||
$rememberMeServices = $container->setDefinition($rememberMeServicesId, new ChildDefinition($templateId));
|
||||
$rememberMeServices->replaceArgument(1, $config['secret']);
|
||||
$rememberMeServices->replaceArgument(2, $id);
|
||||
|
||||
if (isset($config['token_provider'])) {
|
||||
$rememberMeServices->addMethodCall('setTokenProvider', [
|
||||
new Reference($config['token_provider']),
|
||||
]);
|
||||
}
|
||||
|
||||
// remember-me options
|
||||
$rememberMeServices->replaceArgument(3, array_intersect_key($config, $this->options));
|
||||
|
||||
if ($config['user_providers']) {
|
||||
$userProviders = [];
|
||||
foreach ($config['user_providers'] as $providerName) {
|
||||
$userProviders[] = new Reference('security.user.provider.concrete.'.$providerName);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 === \count($userProviders)) {
|
||||
throw new \RuntimeException('You must configure at least one remember-me aware listener (such as form-login) for each firewall that has remember-me enabled.');
|
||||
}
|
||||
|
||||
$rememberMeServices->replaceArgument(0, new IteratorArgument(array_unique($userProviders)));
|
||||
}
|
||||
|
||||
private function createRememberMeListener(ContainerBuilder $container, string $id, string $rememberMeServicesId): void
|
||||
{
|
||||
$container
|
||||
->setDefinition('security.listener.remember_me.'.$id, new ChildDefinition('security.listener.remember_me'))
|
||||
->addTag('kernel.event_subscriber')
|
||||
->replaceArgument(0, new Reference($rememberMeServicesId))
|
||||
->replaceArgument(1, $id)
|
||||
;
|
||||
|
||||
$container
|
||||
->setDefinition('security.logout.listener.remember_me.'.$id, new Definition(RememberMeLogoutListener::class))
|
||||
->addTag('kernel.event_subscriber', ['dispatcher' => 'security.event_dispatcher.'.$id])
|
||||
->addArgument(new Reference($rememberMeServicesId));
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ChildDefinition;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
@ -34,6 +35,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
|
||||
use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder;
|
||||
use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder;
|
||||
use Symfony\Component\Security\Core\User\ChainUserProvider;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Controller\UserValueResolver;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
@ -230,9 +232,16 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
foreach ($providerIds as $userProviderId) {
|
||||
$userProviders[] = new Reference($userProviderId);
|
||||
}
|
||||
$arguments[1] = new IteratorArgument($userProviders);
|
||||
$arguments[1] = $userProviderIteratorsArgument = new IteratorArgument($userProviders);
|
||||
$contextListenerDefinition->setArguments($arguments);
|
||||
|
||||
if (\count($userProviders) > 1) {
|
||||
$container->setDefinition('security.user_providers', new Definition(ChainUserProvider::class, [$userProviderIteratorsArgument]))
|
||||
->setPublic(false);
|
||||
} else {
|
||||
$container->setAlias('security.user_providers', new Alias(current($providerIds)))->setPublic(false);
|
||||
}
|
||||
|
||||
if (1 === \count($providerIds)) {
|
||||
$container->setAlias(UserProviderInterface::class, current($providerIds));
|
||||
}
|
||||
@ -423,16 +432,6 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
// Determine default entry point
|
||||
$configuredEntryPoint = isset($firewall['entry_point']) ? $firewall['entry_point'] : null;
|
||||
|
||||
if ($this->authenticatorManagerEnabled) {
|
||||
// Remember me listener (must be before calling createAuthenticationListeners() to inject remember me services)
|
||||
$container
|
||||
->setDefinition('security.listener.remember_me.'.$id, new ChildDefinition('security.listener.remember_me'))
|
||||
->replaceArgument(0, $id)
|
||||
->addTag('kernel.event_subscriber')
|
||||
->addTag('security.remember_me_aware', ['id' => $id, 'provider' => 'none'])
|
||||
;
|
||||
}
|
||||
|
||||
// Authentication listeners
|
||||
$firewallAuthenticationProviders = [];
|
||||
list($authListeners, $defaultEntryPoint) = $this->createAuthenticationListeners($container, $id, $firewall, $firewallAuthenticationProviders, $defaultProvider, $providerIds, $configuredEntryPoint, $contextListenerId);
|
||||
@ -554,7 +553,7 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
return [$listeners, $defaultEntryPoint];
|
||||
}
|
||||
|
||||
private function getUserProvider(ContainerBuilder $container, string $id, array $firewall, string $factoryKey, ?string $defaultProvider, array $providerIds, ?string $contextListenerId): ?string
|
||||
private function getUserProvider(ContainerBuilder $container, string $id, array $firewall, string $factoryKey, ?string $defaultProvider, array $providerIds, ?string $contextListenerId): string
|
||||
{
|
||||
if (isset($firewall[$factoryKey]['provider'])) {
|
||||
if (!isset($providerIds[$normalizedName = str_replace('-', '_', $firewall[$factoryKey]['provider'])])) {
|
||||
@ -564,13 +563,8 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
return $providerIds[$normalizedName];
|
||||
}
|
||||
|
||||
if ('remember_me' === $factoryKey || 'anonymous' === $factoryKey) {
|
||||
if ('remember_me' === $factoryKey && $contextListenerId) {
|
||||
$container->getDefinition($contextListenerId)->addTag('security.remember_me_aware', ['id' => $id, 'provider' => 'none']);
|
||||
}
|
||||
|
||||
// RememberMeFactory will use the firewall secret when created
|
||||
return null;
|
||||
if ('remember_me' === $factoryKey && $contextListenerId) {
|
||||
$container->getDefinition($contextListenerId)->addTag('security.remember_me_aware', ['id' => $id, 'provider' => 'none']);
|
||||
}
|
||||
|
||||
if ($defaultProvider) {
|
||||
@ -587,6 +581,10 @@ class SecurityExtension extends Extension implements PrependExtensionInterface
|
||||
return $userProvider;
|
||||
}
|
||||
|
||||
if ('remember_me' === $factoryKey || 'anonymous' === $factoryKey) {
|
||||
return 'security.user_providers';
|
||||
}
|
||||
|
||||
throw new InvalidConfigurationException(sprintf('Not configuring explicitly the provider for the "%s" listener on "%s" firewall is ambiguous as there is more than one registered provider.', $factoryKey, $id));
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,8 @@
|
||||
class="Symfony\Component\Security\Http\EventListener\RememberMeListener"
|
||||
abstract="true">
|
||||
<tag name="monolog.logger" channel="security" />
|
||||
<argument/> <!-- provider key -->
|
||||
<argument type="abstract">remember me services</argument>
|
||||
<argument type="abstract">provider key</argument>
|
||||
<argument type="service" id="logger" on-invalid="null" />
|
||||
</service>
|
||||
|
||||
@ -82,5 +83,15 @@
|
||||
<argument type="abstract">secret</argument>
|
||||
<argument type="service" id="security.untracked_token_storage" />
|
||||
</service>
|
||||
|
||||
<service id="security.authenticator.remember_me"
|
||||
class="Symfony\Component\Security\Http\Authenticator\RememberMeAuthenticator"
|
||||
abstract="true">
|
||||
<argument type="abstract">remember me services</argument>
|
||||
<argument>%kernel.secret%</argument>
|
||||
<argument type="service" id="security.token_storage" />
|
||||
<argument type="abstract">options</argument>
|
||||
<argument type="service" id="security.authentication.session_strategy" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
@ -25,7 +25,7 @@ use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface
|
||||
*
|
||||
* @experimental in 5.1
|
||||
*/
|
||||
abstract class AbstractLoginFormAuthenticator extends AbstractAuthenticator implements AuthenticationEntryPointInterface
|
||||
abstract class AbstractLoginFormAuthenticator extends AbstractAuthenticator implements AuthenticationEntryPointInterface, RememberMeAuthenticatorInterface
|
||||
{
|
||||
/**
|
||||
* Return the URL to the login page.
|
||||
@ -46,11 +46,6 @@ abstract class AbstractLoginFormAuthenticator extends AbstractAuthenticator impl
|
||||
return new RedirectResponse($url);
|
||||
}
|
||||
|
||||
public function supportsRememberMe(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to control what happens when the user hits a secure page
|
||||
* but isn't logged in yet.
|
||||
@ -61,4 +56,9 @@ abstract class AbstractLoginFormAuthenticator extends AbstractAuthenticator impl
|
||||
|
||||
return new RedirectResponse($url);
|
||||
}
|
||||
|
||||
public function supportsRememberMe(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -75,9 +75,4 @@ class AnonymousAuthenticator implements AuthenticatorInterface, CustomAuthentica
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function supportsRememberMe(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -102,18 +102,4 @@ interface AuthenticatorInterface
|
||||
* will be authenticated. This makes sense, for example, with an API.
|
||||
*/
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey): ?Response;
|
||||
|
||||
/**
|
||||
* Does this method support remember me cookies?
|
||||
*
|
||||
* Remember me cookie will be set if *all* of the following are met:
|
||||
* A) This method returns true
|
||||
* B) The remember_me key under your firewall is configured
|
||||
* C) The "remember me" functionality is activated. This is usually
|
||||
* done by having a _remember_me checkbox in your form, but
|
||||
* can be configured by the "always_remember_me" and "remember_me_parameter"
|
||||
* parameters under the "remember_me" firewall key
|
||||
* D) The onAuthenticationSuccess method returns a Response object
|
||||
*/
|
||||
public function supportsRememberMe(): bool;
|
||||
}
|
||||
|
@ -94,9 +94,4 @@ class HttpBasicAuthenticator implements AuthenticatorInterface, AuthenticationEn
|
||||
|
||||
return $this->start($request, $exception);
|
||||
}
|
||||
|
||||
public function supportsRememberMe(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Authenticator\Token;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
|
||||
use Symfony\Component\Security\Http\RememberMe\AbstractRememberMeServices;
|
||||
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
|
||||
|
||||
/**
|
||||
* The RememberMe *Authenticator* performs remember me authentication.
|
||||
*
|
||||
* This authenticator is executed whenever a user's session
|
||||
* expired and a remember me cookie was found. This authenticator
|
||||
* then "re-authenticates" the user using the information in the
|
||||
* cookie.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RememberMeAuthenticator implements AuthenticatorInterface
|
||||
{
|
||||
private $rememberMeServices;
|
||||
private $secret;
|
||||
private $tokenStorage;
|
||||
private $options;
|
||||
private $sessionStrategy;
|
||||
|
||||
public function __construct(AbstractRememberMeServices $rememberMeServices, string $secret, TokenStorageInterface $tokenStorage, array $options, ?SessionAuthenticationStrategy $sessionStrategy = null)
|
||||
{
|
||||
$this->rememberMeServices = $rememberMeServices;
|
||||
$this->secret = $secret;
|
||||
$this->tokenStorage = $tokenStorage;
|
||||
$this->options = $options;
|
||||
$this->sessionStrategy = $sessionStrategy;
|
||||
}
|
||||
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
// do not overwrite already stored tokens (i.e. from the session)
|
||||
if (null !== $this->tokenStorage->getToken()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (($cookie = $request->attributes->get(AbstractRememberMeServices::COOKIE_ATTR_NAME)) && null === $cookie->getValue()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$request->cookies->has($this->options['name'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// the `null` return value indicates that this authenticator supports lazy firewalls
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getCredentials(Request $request)
|
||||
{
|
||||
return [
|
||||
'cookie_parts' => explode(AbstractRememberMeServices::COOKIE_DELIMITER, base64_decode($request->cookies->get($this->options['name']))),
|
||||
'request' => $request,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $credentials
|
||||
*/
|
||||
public function getUser($credentials): ?UserInterface
|
||||
{
|
||||
return $this->rememberMeServices->performLogin($credentials['cookie_parts'], $credentials['request']);
|
||||
}
|
||||
|
||||
public function createAuthenticatedToken(UserInterface $user, string $providerKey): TokenInterface
|
||||
{
|
||||
return new RememberMeToken($user, $providerKey, $this->secret);
|
||||
}
|
||||
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
|
||||
{
|
||||
$this->rememberMeServices->loginFail($request, $exception);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey): ?Response
|
||||
{
|
||||
if ($request->hasSession() && $request->getSession()->isStarted()) {
|
||||
$this->sessionStrategy->onAuthentication($request, $token);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Security\Http\Authenticator;
|
||||
|
||||
/**
|
||||
* This interface must be extended if the authenticator supports remember me functionality.
|
||||
*
|
||||
* Remember me cookie will be set if *all* of the following are met:
|
||||
* A) SupportsRememberMe() returns true in the successful authenticator
|
||||
* B) The remember_me key under your firewall is configured
|
||||
* C) The "remember me" functionality is activated. This is usually
|
||||
* done by having a _remember_me checkbox in your form, but
|
||||
* can be configured by the "always_remember_me" and "remember_me_parameter"
|
||||
* parameters under the "remember_me" firewall key
|
||||
* D) The onAuthenticationSuccess method returns a Response object
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*/
|
||||
interface RememberMeAuthenticatorInterface
|
||||
{
|
||||
public function supportsRememberMe(): bool;
|
||||
}
|
@ -5,11 +5,19 @@ namespace Symfony\Component\Security\Http\EventListener;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
|
||||
use Symfony\Component\Security\Http\Authenticator\RememberMeAuthenticatorInterface;
|
||||
use Symfony\Component\Security\Http\Event\LoginFailureEvent;
|
||||
use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
|
||||
use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
|
||||
|
||||
/**
|
||||
* The RememberMe *listener* creates and deletes remember me cookies.
|
||||
*
|
||||
* Upon login success or failure and support for remember me
|
||||
* in the firewall and authenticator, this listener will create
|
||||
* a remember me cookie.
|
||||
* Upon login failure, all remember me cookies are removed.
|
||||
*
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
*
|
||||
* @final
|
||||
@ -17,23 +25,18 @@ use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface;
|
||||
*/
|
||||
class RememberMeListener implements EventSubscriberInterface
|
||||
{
|
||||
private $rememberMeServices;
|
||||
private $providerKey;
|
||||
private $logger;
|
||||
/** @var RememberMeServicesInterface|null */
|
||||
private $rememberMeServices;
|
||||
|
||||
public function __construct(string $providerKey, ?LoggerInterface $logger = null)
|
||||
public function __construct(RememberMeServicesInterface $rememberMeServices, string $providerKey, ?LoggerInterface $logger = null)
|
||||
{
|
||||
$this->rememberMeServices = $rememberMeServices;
|
||||
$this->providerKey = $providerKey;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
||||
public function setRememberMeServices(RememberMeServicesInterface $rememberMeServices): void
|
||||
{
|
||||
$this->rememberMeServices = $rememberMeServices;
|
||||
}
|
||||
|
||||
public function onSuccessfulLogin(LoginSuccessEvent $event): void
|
||||
{
|
||||
if (!$this->isRememberMeEnabled($event->getAuthenticator(), $event->getProviderKey())) {
|
||||
@ -59,15 +62,7 @@ class RememberMeListener implements EventSubscriberInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null === $this->rememberMeServices) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Remember me skipped: it is not configured for the firewall.', ['authenticator' => \get_class($authenticator)]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$authenticator->supportsRememberMe()) {
|
||||
if (!$authenticator instanceof RememberMeAuthenticatorInterface || !$authenticator->supportsRememberMe()) {
|
||||
if (null !== $this->logger) {
|
||||
$this->logger->debug('Remember me skipped: your authenticator does not support it.', ['authenticator' => \get_class($authenticator)]);
|
||||
}
|
||||
|
@ -89,6 +89,11 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface
|
||||
return $this->secret;
|
||||
}
|
||||
|
||||
public function performLogin(array $cookieParts, Request $request): UserInterface
|
||||
{
|
||||
return $this->processAutoLoginCookie($cookieParts, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of RememberMeServicesInterface. Detects whether a remember-me
|
||||
* cookie was set, decodes it, and hands it to subclasses for further processing.
|
||||
|
Reference in New Issue
Block a user