How to Create a Custom Authentication System with Guard
<?php
namespace App\Security\Authenticator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Validator\Validator\Validator\ValidatorInterface;
class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
/**
* @var UserPasswordEncoderInterface
*/
private $encoder;
/**
* @var ValidatorInterface
*/
private $validator;
/**
* FormLoginAuthenticator constructor.
* @param UserPasswordEncoderInterface $encoder
* @param IsTrueValidator $isTrueValidator
*/
public function __construct(UserPasswordEncoderInterface $encoder, ValidatorInterface $validator)
{
$this->encoder = $encoder;
$this->validator = $validator;
}
/**
* Return the URL to the login page.
*
* @return string
*/
protected function getLoginUrl()
{
return '/login';
}
/**
* Does the authenticator support the given Request?
*
* If this returns false, the authenticator will be skipped.
*
* @param Request $request
*
* @return bool
*/
public function supports(Request $request)
{
return true;
}
/**
*
* @param Request $request
*
* @return mixed Any non-null value
*
* @throws \UnexpectedValueException If null is returned
*/
public function getCredentials(Request $request)
{
$violations = $this->validator->validate($request->request->get('g-recaptcha-response'), new IsTrue());
if($violations->count() > 0){
throw new AuthenticationException(self::INVALID_RECAPTCHA);
}
return array(
'username' => $request->request->get('_username'),
'password' => $request->request->get('_password'),
);
}
/**
* Return a UserInterface object based on the credentials.
*
* The *credentials* are the return value from getCredentials()
*
* You may throw an AuthenticationException if you wish. If you return
* null, then a UsernameNotFoundException is thrown for you.
*
* @param mixed $credentials
* @param UserProviderInterface $userProvider
*
* @throws AuthenticationException
*
* @return UserInterface|null
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
return $userProvider->loadUserByUsername($credentials['username']);
}
/**
* Returns true if the credentials are valid.
*
* If any value other than true is returned, authentication will
* fail. You may also throw an AuthenticationException if you wish
* to cause authentication to fail.
*
* The *credentials* are the return value from getCredentials()
*
* @param mixed $credentials
* @param UserInterface $user
*
* @return bool
*
* @throws AuthenticationException
*/
public function checkCredentials($credentials, UserInterface $user)
{
$plainPassword = $credentials['password'];
if (!empty($plainPassword) && !$this->encoder->isPasswordValid($user, $plainPassword)) {
throw new BadCredentialsException();
}
return true;
}
/**
* Called when authentication executed and was successful!
*
* If you return null, the current request will continue, and the user
* will be authenticated. This makes sense, for example, with an API.
*
* @param Request $request
* @param TokenInterface $token
* @param string $providerKey The provider (i.e. firewall) key
*
* @return Response|null
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
return null;
}
}
default services.yaml
providers:
default:
entity:
class: App:User
property: phone
main:
pattern: ^/
anonymous: ~
provider: default
guard:
authenticators:
- App\Security\FormLoginAuthenticator
logout: ~