feat: local user registration
This commit is contained in:
1 parent
8bb7f08074
commit
161029ec7c
29 files changed
+1549
-601
No files matched your search
@@ -12,14 +12,15 @@ use App\BusProNet\Model\CrmAttributes;
|
||||
use App\BusProNet\Model\PersonalData;
|
||||
use App\Entity\User;
|
||||
use App\Htmx\HxRedirectResponse;
|
||||
use App\Service\ProfileCompletenessChecker;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Service\UserBootstrapper;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
|
||||
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
|
||||
@@ -29,6 +30,7 @@ use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
|
||||
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
|
||||
use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
/**
|
||||
* Authenticates users against the local Symfony password hash.
|
||||
@@ -46,8 +48,9 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent
|
||||
private readonly ApiClient $apiClient,
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly Crypt $crypt,
|
||||
private readonly ProfileCompletenessChecker $completenessChecker,
|
||||
private readonly UserPasswordHasherInterface $passwordHasher,
|
||||
private readonly ValidatorInterface $validator,
|
||||
private readonly UserBootstrapper $userBootstrapper,
|
||||
private readonly LoggerInterface $authLogger,
|
||||
) {
|
||||
}
|
||||
@@ -62,12 +65,13 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent
|
||||
$email = trim($request->request->getString('_username'));
|
||||
$passwordPlain = trim($request->request->getString('_password'));
|
||||
|
||||
/** @var UserRepository $userRepository */
|
||||
$userRepository = $this->entityManager->getRepository(User::class);
|
||||
$user = $userRepository->findOneBy(['email' => $email]);
|
||||
$user = $userRepository->findOneByNormalizedEmail($email);
|
||||
|
||||
if (null === $user) {
|
||||
// First login for this email: prove credentials against BPN,
|
||||
// then create the local account from the returned customer data.
|
||||
// Legacy fallback for accounts that were not created locally yet:
|
||||
// prove credentials against BPN, then bootstrap the local account.
|
||||
$user = $this->bootstrapUser($email, $passwordPlain);
|
||||
} else {
|
||||
if (true === $user->hasLocalPasswordHash()) {
|
||||
@@ -86,6 +90,8 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent
|
||||
|
||||
$user->setPassword($this->passwordHasher->hashPassword($user, $passwordPlain));
|
||||
}
|
||||
|
||||
$this->refreshBpnSnapshot($user);
|
||||
}
|
||||
|
||||
$user->setLastLoginAt(new \DateTimeImmutable());
|
||||
@@ -114,25 +120,76 @@ class BpnAuthenticator extends AbstractLoginFormAuthenticator implements Authent
|
||||
throw new CustomUserMessageAuthenticationException($message);
|
||||
}
|
||||
|
||||
if (false === $personalData instanceof PersonalData || false === $crmAttributes instanceof CrmAttributes) {
|
||||
if (!$personalData instanceof PersonalData || !$crmAttributes instanceof CrmAttributes) {
|
||||
throw new CustomUserMessageAuthenticationException('Benutzername oder Passwort ist nicht korrekt.');
|
||||
}
|
||||
|
||||
$user = new User($email);
|
||||
$passwordHash = $this->passwordHasher->hashPassword($user, $passwordPlain);
|
||||
$profileComplete = 0 === $this->validator->validate($personalData, null, ['personal_data'])->count();
|
||||
$this->userBootstrapper->bootstrap(
|
||||
$user,
|
||||
$passwordHash,
|
||||
$personalData->addressId,
|
||||
$personalData->personId,
|
||||
$crmAttributes->roles,
|
||||
$crmAttributes->hotelCodes,
|
||||
$profileComplete,
|
||||
);
|
||||
$this->entityManager->persist($user);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
private function refreshBpnSnapshot(User $user): void
|
||||
{
|
||||
try {
|
||||
$personalData = $this->apiClient->getPersonalData(
|
||||
$user->getUserIdentifier(),
|
||||
$user->getAddressId(),
|
||||
$user->getPersonId(),
|
||||
);
|
||||
} catch (ApiClientException $e) {
|
||||
$message = $this->isConnectionError($e)
|
||||
? 'Der Server ist momentan nicht erreichbar. Bitte versuche es später erneut.'
|
||||
: $e->getMessage();
|
||||
|
||||
throw new CustomUserMessageAuthenticationException($message);
|
||||
}
|
||||
|
||||
if (!$personalData instanceof PersonalData) {
|
||||
throw new CustomUserMessageAuthenticationException('Benutzername oder Passwort ist nicht korrekt.');
|
||||
}
|
||||
|
||||
$profileComplete = 0 === $this->validator->validate($personalData, null, ['personal_data'])->count();
|
||||
$user
|
||||
// Persist the local hash immediately so subsequent logins no longer
|
||||
// depend on the legacy BPN password format.
|
||||
->setPassword($this->passwordHasher->hashPassword($user, $passwordPlain))
|
||||
->setPersonId($personalData->personId)
|
||||
->setAddressId($personalData->addressId)
|
||||
->setRoles($crmAttributes->roles)
|
||||
->setHotelCodes($crmAttributes->hotelCodes)
|
||||
->setProfileComplete($this->completenessChecker->isComplete($personalData))
|
||||
->setPersonId($personalData->personId)
|
||||
->setProfileComplete($profileComplete)
|
||||
;
|
||||
|
||||
return $user;
|
||||
try {
|
||||
$crmAttributes = $this->apiClient->getCrmAttributes(
|
||||
$user->getUserIdentifier(),
|
||||
$user->getAddressId(),
|
||||
$user->getPersonId(),
|
||||
);
|
||||
} catch (ApiClientException $e) {
|
||||
$message = $this->isConnectionError($e)
|
||||
? 'Der Server ist momentan nicht erreichbar. Bitte versuche es später erneut.'
|
||||
: $e->getMessage();
|
||||
|
||||
throw new CustomUserMessageAuthenticationException($message);
|
||||
}
|
||||
|
||||
if (!$crmAttributes instanceof CrmAttributes) {
|
||||
throw new CustomUserMessageAuthenticationException('Benutzername oder Passwort ist nicht korrekt.');
|
||||
}
|
||||
|
||||
$user
|
||||
->setRoles($crmAttributes->roles)
|
||||
->setHotelCodes($crmAttributes->hotelCodes)
|
||||
;
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||
|
||||
Reference in new issue
Block a user