Also use authentication failure/success handlers in FormLoginAuthenticator
This commit is contained in:
parent
0fe5083a3e
commit
9ea32c4ed3
@ -30,6 +30,7 @@ abstract class AbstractFactory implements SecurityFactoryInterface
|
||||
'check_path' => '/login_check',
|
||||
'use_forward' => false,
|
||||
'require_previous_session' => false,
|
||||
'login_path' => '/login',
|
||||
];
|
||||
|
||||
protected $defaultSuccessHandlerOptions = [
|
||||
|
@ -100,12 +100,13 @@ class FormLoginFactory extends AbstractFactory implements AuthenticatorFactoryIn
|
||||
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);
|
||||
$options = array_merge($defaultOptions, array_intersect_key($config, $defaultOptions));
|
||||
$options = array_intersect_key($config, $this->options);
|
||||
$container
|
||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.form_login'))
|
||||
->replaceArgument(1, new Reference($userProviderId))
|
||||
->replaceArgument(2, $options);
|
||||
->replaceArgument(2, new Reference($this->createAuthenticationSuccessHandler($container, $id, $config)))
|
||||
->replaceArgument(3, new Reference($this->createAuthenticationFailureHandler($container, $id, $config)))
|
||||
->replaceArgument(4, $options);
|
||||
|
||||
return $authenticatorId;
|
||||
}
|
||||
|
@ -95,6 +95,8 @@
|
||||
abstract="true">
|
||||
<argument type="service" id="security.http_utils" />
|
||||
<argument type="abstract">user provider</argument>
|
||||
<argument type="abstract">authentication success handler</argument>
|
||||
<argument type="abstract">authentication failure handler</argument>
|
||||
<argument type="abstract">options</argument>
|
||||
</service>
|
||||
|
||||
|
@ -30,7 +30,7 @@ abstract class AbstractLoginFormAuthenticator extends AbstractAuthenticator impl
|
||||
/**
|
||||
* Return the URL to the login page.
|
||||
*/
|
||||
abstract protected function getLoginUrl(): string;
|
||||
abstract protected function getLoginUrl(Request $request): string;
|
||||
|
||||
/**
|
||||
* Override to change what happens after a bad username/password is submitted.
|
||||
@ -41,7 +41,7 @@ abstract class AbstractLoginFormAuthenticator extends AbstractAuthenticator impl
|
||||
$request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);
|
||||
}
|
||||
|
||||
$url = $this->getLoginUrl();
|
||||
$url = $this->getLoginUrl($request);
|
||||
|
||||
return new RedirectResponse($url);
|
||||
}
|
||||
@ -52,7 +52,7 @@ abstract class AbstractLoginFormAuthenticator extends AbstractAuthenticator impl
|
||||
*/
|
||||
public function start(Request $request, AuthenticationException $authException = null): Response
|
||||
{
|
||||
$url = $this->getLoginUrl();
|
||||
$url = $this->getLoginUrl($request);
|
||||
|
||||
return new RedirectResponse($url);
|
||||
}
|
||||
|
@ -16,13 +16,15 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
|
||||
use Symfony\Component\Security\Http\HttpUtils;
|
||||
use Symfony\Component\Security\Http\ParameterBagUtils;
|
||||
use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
||||
|
||||
/**
|
||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
||||
@ -33,34 +35,32 @@ use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
||||
*/
|
||||
class FormLoginAuthenticator extends AbstractLoginFormAuthenticator implements PasswordAuthenticatedInterface, CsrfProtectedAuthenticatorInterface
|
||||
{
|
||||
use TargetPathTrait;
|
||||
|
||||
private $options;
|
||||
private $httpUtils;
|
||||
private $userProvider;
|
||||
private $successHandler;
|
||||
private $failureHandler;
|
||||
private $options;
|
||||
|
||||
public function __construct(HttpUtils $httpUtils, UserProviderInterface $userProvider, array $options)
|
||||
public function __construct(HttpUtils $httpUtils, UserProviderInterface $userProvider, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options)
|
||||
{
|
||||
$this->httpUtils = $httpUtils;
|
||||
$this->userProvider = $userProvider;
|
||||
$this->successHandler = $successHandler;
|
||||
$this->failureHandler = $failureHandler;
|
||||
$this->options = array_merge([
|
||||
'username_parameter' => '_username',
|
||||
'password_parameter' => '_password',
|
||||
'csrf_parameter' => '_csrf_token',
|
||||
'csrf_token_id' => 'authenticate',
|
||||
'check_path' => '/login_check',
|
||||
'post_only' => true,
|
||||
|
||||
'always_use_default_target_path' => false,
|
||||
'default_target_path' => '/',
|
||||
'login_path' => '/login',
|
||||
'target_path_parameter' => '_target_path',
|
||||
'use_referer' => false,
|
||||
'csrf_parameter' => '_csrf_token',
|
||||
'csrf_token_id' => 'authenticate',
|
||||
], $options);
|
||||
$this->userProvider = $userProvider;
|
||||
}
|
||||
|
||||
protected function getLoginUrl(): string
|
||||
protected function getLoginUrl(Request $request): string
|
||||
{
|
||||
return $this->options['login_path'];
|
||||
return $this->httpUtils->generateUri($request, $this->options['login_path']);
|
||||
}
|
||||
|
||||
public function supports(Request $request): bool
|
||||
@ -122,36 +122,13 @@ class FormLoginAuthenticator extends AbstractLoginFormAuthenticator implements P
|
||||
return new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey): Response
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey): ?Response
|
||||
{
|
||||
return $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request, $providerKey));
|
||||
return $this->successHandler->onAuthenticationSuccess($request, $token);
|
||||
}
|
||||
|
||||
private function determineTargetUrl(Request $request, string $providerKey)
|
||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response
|
||||
{
|
||||
if ($this->options['always_use_default_target_path']) {
|
||||
return $this->options['default_target_path'];
|
||||
}
|
||||
|
||||
if ($targetUrl = ParameterBagUtils::getRequestParameterValue($request, $this->options['target_path_parameter'])) {
|
||||
return $targetUrl;
|
||||
}
|
||||
|
||||
if ($targetUrl = $this->getTargetPath($request->getSession(), $providerKey)) {
|
||||
$this->removeTargetPath($request->getSession(), $providerKey);
|
||||
|
||||
return $targetUrl;
|
||||
}
|
||||
|
||||
if ($this->options['use_referer'] && $targetUrl = $request->headers->get('Referer')) {
|
||||
if (false !== $pos = strpos($targetUrl, '?')) {
|
||||
$targetUrl = substr($targetUrl, 0, $pos);
|
||||
}
|
||||
if ($targetUrl && $targetUrl !== $this->httpUtils->generateUri($request, $this->options['login_path'])) {
|
||||
return $targetUrl;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->options['default_target_path'];
|
||||
return $this->failureHandler->onAuthenticationFailure($request, $exception);
|
||||
}
|
||||
}
|
||||
|
@ -17,17 +17,23 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
|
||||
use Symfony\Component\Security\Http\Authenticator\FormLoginAuthenticator;
|
||||
use Symfony\Component\Security\Http\HttpUtils;
|
||||
|
||||
class FormLoginAuthenticatorTest extends TestCase
|
||||
{
|
||||
private $userProvider;
|
||||
private $successHandler;
|
||||
private $failureHandler;
|
||||
private $authenticator;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->userProvider = $this->createMock(UserProviderInterface::class);
|
||||
$this->successHandler = $this->createMock(AuthenticationSuccessHandlerInterface::class);
|
||||
$this->failureHandler = $this->createMock(AuthenticationFailureHandlerInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,7 +129,7 @@ class FormLoginAuthenticatorTest extends TestCase
|
||||
|
||||
private function setUpAuthenticator(array $options = [])
|
||||
{
|
||||
$this->authenticator = new FormLoginAuthenticator(new HttpUtils(), $this->userProvider, $options);
|
||||
$this->authenticator = new FormLoginAuthenticator(new HttpUtils(), $this->userProvider, $this->successHandler, $this->failureHandler, $options);
|
||||
}
|
||||
|
||||
private function createSession()
|
||||
|
Reference in New Issue
Block a user