<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
class SocialAuthenticator extends OAuth2Authenticator implements AuthenticationEntrypointInterface
{
private $clientRegistry;
private $entityManager;
private $router;
private $passwordEncoder;
public function __construct(ClientRegistry $clientRegistry, EntityManagerInterface $entityManager, RouterInterface $router, UserPasswordHasherInterface $passwordEncoder)
{
$this->clientRegistry = $clientRegistry;
$this->entityManager = $entityManager;
$this->router = $router;
$this->passwordEncoder = $passwordEncoder;
}
public function supports(Request $request): ?bool
{
// continue ONLY if the current ROUTE matches the check ROUTE
return $request->attributes->get('_route') === 'connect_facebook_check'
|| $request->attributes->get('_route') === 'connect_google_check';
}
public function authenticate(Request $request): Passport
{
if ($request->attributes->get('_route') === 'connect_facebook_check') {
$client = $this->clientRegistry->getClient('facebook_main');
} elseif ($request->attributes->get('_route') === 'connect_google_check') {
$client = $this->clientRegistry->getClient('google_main');
}
$accessToken = $this->fetchAccessToken($client);
return new SelfValidatingPassport(
new UserBadge($accessToken->getToken(), function() use ($accessToken, $client) {
/** @var FacebookUser $facebookUser */
$facebookUser = $client->fetchUserFromToken($accessToken);
$email = $facebookUser->getEmail();
$firstName = $facebookUser->getFirstName();
$lastName = $facebookUser->getLastName();
$social_id = $facebookUser->getId();
$role = 'ROLE_PARENT';
// Generate random bytes
$randomBytes = random_bytes(10);
// Convert random bytes to a password using base64 encoding
$password = base64_encode($randomBytes);
// Optionally, you can remove characters that are not suitable for a password
$password = strtr($password, '+/', '-_');
// 1) have they logged in with Facebook before? Easy!
/* $existingUser = $this->entityManager->getRepository(User::class)->findOneBy(['facebookId' => $facebookUser->getId()]);
if ($existingUser) {
return $existingUser;
}
*/
// 2) do we have a matching user by email?
$user = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $email]);
if ($user) {
return $user;
}
// 3) Maybe you just want to "register" them by creating
// a User object
$user = new User();
$user->setNom($lastName);
$user->setPrenom($firstName);
$user->setUsername($email);
$user->setMailnotif(1);
$user->setShowpubprod(true);
//$user->setNummobile('');
$user->setEmail(trim($email));
$user->setDateCreation(new \DateTime());
$user->addRole($role);
$user->setPassword(
$this->passwordEncoder->hashPassword(
$user,
$password
)
);
$this->entityManager->persist($user);
$this->entityManager->flush();
return $user;
})
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
// change "app_homepage" to some route in your app
$targetUrl = $this->router->generate('CodeSejour');
return new RedirectResponse($targetUrl);
// or, on success, let the request continue to be handled by the controller
//return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$message = strtr($exception->getMessageKey(), $exception->getMessageData());
return new Response($message, Response::HTTP_FORBIDDEN);
}
/**
* Called when authentication is needed, but it's not sent.
* This redirects to the 'login'.
*/
public function start(Request $request, AuthenticationException $authException = null): Response
{
return new RedirectResponse(
'/connect/', // might be the site, where users choose their oauth provider
Response::HTTP_TEMPORARY_REDIRECT
);
}
}