<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Security\Authenticator\SocialAuthenticator;
use KnpU\OAuth2ClientBundle\Client\Provider\FacebookClient;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use League\OAuth2\Client\Provider\FacebookUser;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
class FacebookAuthenticator extends SocialAuthenticator
{
/** @var ClientRegistry */
private $clientRegistry;
/** @var EntityManagerInterface */
private $entityManager;
/** @var RouterInterface */
private $router;
/** @var User */
private $user = null;
/** @var UserPasswordHasherInterface */
private $userPasswordHasher;
/** @var FlashBagInterface */
private $flashBag;
/**
* FacebookAuthenticator constructor.
*
* @param ClientRegistry $clientRegistry
* @param RouterInterface $router
* @param EntityManagerInterface $entityManager
* @param UserPasswordHasherInterface $userPasswordHasher
* @param FlashBagInterface $flashBag
*/
public function __construct(
ClientRegistry $clientRegistry,
EntityManagerInterface $entityManager,
RouterInterface $router,
UserPasswordHasherInterface $userPasswordHasher,
FlashBagInterface $flashBag
) {
$this->clientRegistry = $clientRegistry;
$this->router = $router;
$this->entityManager = $entityManager;
$this->userPasswordHasher = $userPasswordHasher;
$this->flashBag = $flashBag;
}
/**
* @param Request $request
* @return bool
*/
public function supports(Request $request)
{
// continue ONLY if the current ROUTE matches the check ROUTE
return $request->attributes->get('_route') === 'connect_facebook_check';
}
/**
* @param Request $request
* @return \League\OAuth2\Client\Token\AccessToken|mixed
*/
public function getCredentials(Request $request)
{
// this method is only called if supports() returns true
return $this->fetchAccessToken($this->getFacebookClient());
}
/**
* @param mixed $credentials
* @param UserProviderInterface $userProvider
* @return User|null|object|\Symfony\Component\Security\Core\User\UserInterface
*/
public function getUser($credentials, UserProviderInterface $userProvider)
{
/** @var FacebookUser $facebookUser */
$facebookUser = $this->getFacebookClient()->fetchUserFromToken($credentials);
$facebookId = $facebookUser->getId();
$email = $facebookUser->getEmail();
$user = $this->entityManager->getRepository(User::class)->findOneBy(['facebookId' => $facebookId]);
if (null === $user) {
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $email]);
if (null === $user) {
throw new UserNotFoundException;
// $firstname = $facebookUser->getFirstName();
// $lastname = $facebookUser->getLastName();
// $profileUrl = $facebookUser->getPictureUrl();
// $gender = $facebookUser->getGender();
// $genders = ['male' => 'm', 'female' => 'f'];
// /** @var User $user */
// $user = new User();
// $user->setEmail($email);
// $user->setRoles(['ROLE_USER']);
// $user->setPassword($this->passwordEncoder->encodePassword($user, 'ayoub123'));
// $user->setIsVerified(true);
// $user->setFirstname($firstname);
// $user->setLastname($lastname);
// $user->setProfileUrl($profileUrl);
// $user->setFacebookId($facebookId);
// if (isset($genders[$gender])) {
// $user->setGender($genders[$gender]);
// }
// $this->entityManager->persist($user);
}
$user->setFacebookId($facebookId);
$this->entityManager->flush();
}
$this->user = $user;
return $userProvider->loadUserByIdentifier($user->getUsername());
}
/**
* @return FacebookClient
*/
private function getFacebookClient()
{
return $this->clientRegistry->getClient('facebook');
}
/**
* @param Request $request
* @param TokenInterface $token
* @param string $providerKey
* @return null|Response
*/
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
// on success, let the request continue
$this->user->setLastLogin(new \DateTimeImmutable());
$this->entityManager->flush();
return null;
}
/**
* @param Request $request
* @param AuthenticationException $exception
* @return RedirectResponse
*/
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): RedirectResponse
{
// $message = strtr($exception->getMessageKey(), $exception->getMessageData());
$this->flashBag->add('danger', 'Votre compte Facebook n\'est pas autorisé');
return new RedirectResponse($this->router->generate('app_login'));
}
/**
* Called when authentication is needed, but it's not sent.
* This redirects to the 'login'.
*
* @param Request $request
* @param AuthenticationException|null $authException
*
* @return RedirectResponse
*/
public function start(Request $request, AuthenticationException $authException = null)
{
return new RedirectResponse(
'/connect/', // might be the site, where users choose their oauth provider
Response::HTTP_TEMPORARY_REDIRECT
);
}
}