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',
|
'check_path' => '/login_check',
|
||||||
'use_forward' => false,
|
'use_forward' => false,
|
||||||
'require_previous_session' => false,
|
'require_previous_session' => false,
|
||||||
|
'login_path' => '/login',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $defaultSuccessHandlerOptions = [
|
protected $defaultSuccessHandlerOptions = [
|
||||||
|
@ -100,12 +100,13 @@ class FormLoginFactory extends AbstractFactory implements AuthenticatorFactoryIn
|
|||||||
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;
|
$authenticatorId = 'security.authenticator.form_login.'.$id;
|
||||||
$defaultOptions = array_merge($this->defaultSuccessHandlerOptions, $this->options);
|
$options = array_intersect_key($config, $this->options);
|
||||||
$options = array_merge($defaultOptions, array_intersect_key($config, $defaultOptions));
|
|
||||||
$container
|
$container
|
||||||
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.form_login'))
|
->setDefinition($authenticatorId, new ChildDefinition('security.authenticator.form_login'))
|
||||||
->replaceArgument(1, new Reference($userProviderId))
|
->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;
|
return $authenticatorId;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,8 @@
|
|||||||
abstract="true">
|
abstract="true">
|
||||||
<argument type="service" id="security.http_utils" />
|
<argument type="service" id="security.http_utils" />
|
||||||
<argument type="abstract">user provider</argument>
|
<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>
|
<argument type="abstract">options</argument>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ abstract class AbstractLoginFormAuthenticator extends AbstractAuthenticator impl
|
|||||||
/**
|
/**
|
||||||
* Return the URL to the login page.
|
* 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.
|
* 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);
|
$request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = $this->getLoginUrl();
|
$url = $this->getLoginUrl($request);
|
||||||
|
|
||||||
return new RedirectResponse($url);
|
return new RedirectResponse($url);
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ abstract class AbstractLoginFormAuthenticator extends AbstractAuthenticator impl
|
|||||||
*/
|
*/
|
||||||
public function start(Request $request, AuthenticationException $authException = null): Response
|
public function start(Request $request, AuthenticationException $authException = null): Response
|
||||||
{
|
{
|
||||||
$url = $this->getLoginUrl();
|
$url = $this->getLoginUrl($request);
|
||||||
|
|
||||||
return new RedirectResponse($url);
|
return new RedirectResponse($url);
|
||||||
}
|
}
|
||||||
|
@ -16,13 +16,15 @@ use Symfony\Component\HttpFoundation\Response;
|
|||||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
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\Exception\BadCredentialsException;
|
||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
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\HttpUtils;
|
||||||
use Symfony\Component\Security\Http\ParameterBagUtils;
|
use Symfony\Component\Security\Http\ParameterBagUtils;
|
||||||
use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Wouter de Jong <wouter@wouterj.nl>
|
* @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
|
class FormLoginAuthenticator extends AbstractLoginFormAuthenticator implements PasswordAuthenticatedInterface, CsrfProtectedAuthenticatorInterface
|
||||||
{
|
{
|
||||||
use TargetPathTrait;
|
|
||||||
|
|
||||||
private $options;
|
|
||||||
private $httpUtils;
|
private $httpUtils;
|
||||||
private $userProvider;
|
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->httpUtils = $httpUtils;
|
||||||
|
$this->userProvider = $userProvider;
|
||||||
|
$this->successHandler = $successHandler;
|
||||||
|
$this->failureHandler = $failureHandler;
|
||||||
$this->options = array_merge([
|
$this->options = array_merge([
|
||||||
'username_parameter' => '_username',
|
'username_parameter' => '_username',
|
||||||
'password_parameter' => '_password',
|
'password_parameter' => '_password',
|
||||||
'csrf_parameter' => '_csrf_token',
|
'check_path' => '/login_check',
|
||||||
'csrf_token_id' => 'authenticate',
|
|
||||||
'post_only' => true,
|
'post_only' => true,
|
||||||
|
|
||||||
'always_use_default_target_path' => false,
|
'csrf_parameter' => '_csrf_token',
|
||||||
'default_target_path' => '/',
|
'csrf_token_id' => 'authenticate',
|
||||||
'login_path' => '/login',
|
|
||||||
'target_path_parameter' => '_target_path',
|
|
||||||
'use_referer' => false,
|
|
||||||
], $options);
|
], $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
|
public function supports(Request $request): bool
|
||||||
@ -122,36 +122,13 @@ class FormLoginAuthenticator extends AbstractLoginFormAuthenticator implements P
|
|||||||
return new UsernamePasswordToken($user, null, $providerKey, $user->getRoles());
|
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->failureHandler->onAuthenticationFailure($request, $exception);
|
||||||
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'];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,17 +17,23 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
|||||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
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\Authenticator\FormLoginAuthenticator;
|
||||||
use Symfony\Component\Security\Http\HttpUtils;
|
use Symfony\Component\Security\Http\HttpUtils;
|
||||||
|
|
||||||
class FormLoginAuthenticatorTest extends TestCase
|
class FormLoginAuthenticatorTest extends TestCase
|
||||||
{
|
{
|
||||||
private $userProvider;
|
private $userProvider;
|
||||||
|
private $successHandler;
|
||||||
|
private $failureHandler;
|
||||||
private $authenticator;
|
private $authenticator;
|
||||||
|
|
||||||
protected function setUp(): void
|
protected function setUp(): void
|
||||||
{
|
{
|
||||||
$this->userProvider = $this->createMock(UserProviderInterface::class);
|
$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 = [])
|
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()
|
private function createSession()
|
||||||
|
Reference in New Issue
Block a user