src/Security/GoogleAuthenticator.php line 34
<?php
namespace App\Security;
use App\Entity\User; // your user entity
use App\Service\UserUpkeep;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use League\OAuth2\Client\Provider\GoogleUser;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\MessageDigestPasswordHasher;
use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactory;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher;
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\Core\User\InMemoryUser;
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;
class GoogleAuthenticator extends OAuth2Authenticator
{
private $clientRegistry;
private $entityManager;
private $router;
private $userUpkeep;
private $userPasswordHasherInterface;
public function __construct(ClientRegistry $clientRegistry, EntityManagerInterface $entityManager, RouterInterface $router, UserUpkeep $userUpkeep, UserPasswordHasherInterface $userPasswordHasherInterface, ParameterBagInterface $params)
{
$this->clientRegistry = $clientRegistry;
$this->entityManager = $entityManager;
$this->router = $router;
$this->userUpkeep = $userUpkeep;
$this->userPasswordHasherInterface = $userPasswordHasherInterface;
$this->params = $params;
}
public function supports(Request $request): ?bool
{
// continue ONLY if the current ROUTE matches the check ROUTE
return $request->attributes->get('_route') === 'connect_google_check';
}
public function authenticate(Request $request): Passport
{
$client = $this->clientRegistry->getClient('google_main');
$accessToken = $this->fetchAccessToken($client);
return new SelfValidatingPassport(
new UserBadge($accessToken->getToken(), function() use ($accessToken, $client) {
/** @var GoogleUser $googleUser */
$googleUser = $client->fetchUserFromToken($accessToken);
$email = $googleUser->getEmail();
// 1) have they logged in with Google before? Easy!
$existingUser = $this->entityManager->getRepository(User::class)->findOneBy(['googleId' => $googleUser->getId()]);
if ($existingUser) {
$this->_generateGameToken($existingUser, $this->entityManager);
return $existingUser;
}
// 2) do we have a matching user by email?
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $email]);
if($user) {
$user->setGoogleId($googleUser->getId());
$this->_generateGameToken($user, $this->entityManager);
} else {
// Create a new User
$user = new User();
$user->setEmail($email);
$user->setGoogleId($googleUser->getId());
$user->setPassword($this->userPasswordHasherInterface->hashPassword($user, $this->_generateRandomString(10)));
$this->entityManager->persist($user);
$this->userUpkeep->addStartingEquipment($user);
$this->userUpkeep->addTemplateStats($user);
$this->userUpkeep->addUserGearSlots($user);
$this->_generateGameToken($user, $this->entityManager);
$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('default', ['domain' => $this->params->get('app.domain')]);
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);
}
private function _generateRandomString($length = 10) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
private function _generateGameToken(User $user, EntityManagerInterface $entityManager) {
// Set a new game token on login
$gameToken = hash('sha256', $this->_generateRandomString() . $user->getEmail());
$user->setGameToken($gameToken);
$this->entityManager->persist($user);
$this->entityManager->flush();
}
// private function _generatePassword(User $user, string $password, UserPasswordHasherInterface $userPasswordHasherInterface) {
// return $userPasswordHasherInterface->hashPassword(
// $user,
// $password
// );
// }
}