chore (login) #43 : remaniement connexion sql, passage à 1 requête au lieu de 2 pour performances
This commit is contained in:
parent
fe4d683c20
commit
d707a91694
@ -12,7 +12,6 @@ class SQLLoginConnect extends AbstractController
|
||||
/**
|
||||
* Méthode qui crée l'unique instance de la classe
|
||||
* si elle n'existe pas encore puis la retourne.
|
||||
*
|
||||
*/
|
||||
public static function getInstance(): SQLLoginConnect
|
||||
{
|
||||
@ -25,6 +24,12 @@ class SQLLoginConnect extends AbstractController
|
||||
|
||||
public function connect($urlDatabase, $dbUser, $dbPassword): PDO
|
||||
{
|
||||
return new PDO($urlDatabase, $dbUser, $dbPassword);
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_TIMEOUT => 5,
|
||||
PDO::ATTR_PERSISTENT => false,
|
||||
];
|
||||
|
||||
return new PDO($urlDatabase, $dbUser, $dbPassword, $options);
|
||||
}
|
||||
}
|
||||
|
@ -72,33 +72,37 @@ class SQLLoginRequest
|
||||
return $this->config[self::SUBJECT_REWRITE_EXPRESSION];
|
||||
}
|
||||
|
||||
public function getRequestScope(): string
|
||||
private function getDataFields(): array
|
||||
{
|
||||
$scope = '';
|
||||
if (!$this->config[self::DATA_TO_FETCH]) {
|
||||
throw new NullDataToFetchException();
|
||||
}
|
||||
|
||||
foreach ($this->config[self::DATA_TO_FETCH] as $data) {
|
||||
$scope .= $data.',';
|
||||
}
|
||||
// On enlève la dernière virgule
|
||||
$scope = substr($scope, 0, -1);
|
||||
|
||||
return 'SELECT '.$scope.' FROM '.$this->getTableName().' WHERE '.$this->getLoginColumnName().' = :'.$this->getLoginColumnName().';';
|
||||
return $this->config[self::DATA_TO_FETCH];
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction de la string pour la requête préparée selon la configuration yaml
|
||||
* intègre la récupération du mot de passe hashé, du salt et de besoin d'upgrade de la méthode de hashage
|
||||
*/
|
||||
public function getRequestPassword(): string
|
||||
private function getPasswordFields(): array
|
||||
{
|
||||
$fields = $this->getPasswordColumnName();
|
||||
$fields[] = $this->getPasswordColumnName();
|
||||
if (!empty($this->getSaltColumnName())) {
|
||||
$fields .= ', '.$this->getSaltColumnName();
|
||||
$fields[] = $this->getSaltColumnName();
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction de la string pour la requête préparée selon la configuration yaml
|
||||
* intègre la récupération du mot de passe hashé, du salt et de besoin d'upgrade de la méthode de hashage
|
||||
*/
|
||||
public function getDatasRequest(): string
|
||||
{
|
||||
$fields = join(',', array_merge($this->getPasswordFields(), $this->getDataFields()));
|
||||
|
||||
return 'SELECT '.$fields.' FROM '.$this->getTableName().' WHERE '.$this->getLoginColumnName().' = :'.$this->getLoginColumnName().';';
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use App\SQLLogin\Exception\DataToFetchConfigurationException;
|
||||
use App\SQLLogin\Exception\InvalidSQLPasswordException;
|
||||
use App\SQLLogin\Exception\LoginElementsConfigurationException;
|
||||
use App\SQLLogin\Exception\SecurityPatternConfigurationException;
|
||||
use App\SQLLogin\SQLLoginRequest;
|
||||
use Exception;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@ -34,12 +35,18 @@ class SQLLoginUserAuthenticator extends AbstractLoginFormAuthenticator
|
||||
private string $baseUrl;
|
||||
private SQLLoginService $sqlLoginService;
|
||||
private PasswordEncoder $passwordHasher;
|
||||
private SQLLoginRequest $sqlLoginRequest;
|
||||
|
||||
public function __construct(string $baseUrl, SQLLoginService $sqlLoginService, PasswordEncoder $passwordHasher)
|
||||
{
|
||||
public function __construct(
|
||||
string $baseUrl,
|
||||
SQLLoginService $sqlLoginService,
|
||||
PasswordEncoder $passwordHasher,
|
||||
SQLLoginRequest $sqlLoginRequest
|
||||
) {
|
||||
$this->baseUrl = $baseUrl;
|
||||
$this->sqlLoginService = $sqlLoginService;
|
||||
$this->passwordHasher = $passwordHasher;
|
||||
$this->sqlLoginRequest = $sqlLoginRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,14 +79,20 @@ class SQLLoginUserAuthenticator extends AbstractLoginFormAuthenticator
|
||||
$rememberMe = isset($form['_remember_me']) ? true : false;
|
||||
$session = $request->getSession();
|
||||
try {
|
||||
// requête préparée
|
||||
list($remoteHashedPassword, $remoteSalt) = $this->sqlLoginService->fetchPassword($login);
|
||||
$datas = $this->sqlLoginService->fetchPasswordAndDatas($login);
|
||||
$remoteHashedPassword = $datas[$this->sqlLoginRequest->getPasswordColumnName()];
|
||||
unset($datas[$this->sqlLoginRequest->getPasswordColumnName()]);
|
||||
$remoteSalt = $datas[$this->sqlLoginRequest->getSaltColumnName()];
|
||||
unset($datas[$this->sqlLoginRequest->getSaltColumnName()]);
|
||||
} catch (DatabaseConnectionException $e) {
|
||||
$session->set(self::ERROR_PDO, true);
|
||||
throw new AuthenticationException();
|
||||
} catch (LoginElementsConfigurationException $e) {
|
||||
$session->set(self::ERROR_CONFIGURATION, true);
|
||||
throw new AuthenticationException();
|
||||
} catch (DataToFetchConfigurationException $e) {
|
||||
$session->set(self::ERROR_DATA_TO_FETCH_CONFIGURATION, true);
|
||||
throw new AuthenticationException();
|
||||
} catch (Exception $exception) {
|
||||
$request->getSession()->set(self::ERROR_LOGIN, true);
|
||||
throw new AuthenticationException();
|
||||
@ -92,8 +105,7 @@ class SQLLoginUserAuthenticator extends AbstractLoginFormAuthenticator
|
||||
try {
|
||||
// Comparaison remote hash et hash du input password + salt
|
||||
$this->passwordHasher->verify($remoteHashedPassword, $plaintextPassword, $remoteSalt);
|
||||
$attributes = $this->sqlLoginService->fetchDatas($login);
|
||||
$user = new User($login, $remoteHashedPassword, $attributes, $rememberMe);
|
||||
$user = new User($login, $remoteHashedPassword, $datas, $rememberMe);
|
||||
|
||||
$loader = function (string $userIdentifier) use ($user) {
|
||||
return $user->getLogin() == $userIdentifier ? $user : null;
|
||||
|
@ -8,7 +8,6 @@ use App\SQLLogin\Exception\LoginElementsConfigurationException;
|
||||
use App\SQLLogin\Exception\NullDataToFetchException;
|
||||
use App\SQLLogin\SQLLoginConnect;
|
||||
use App\SQLLogin\SQLLoginRequest;
|
||||
use Exception;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
@ -16,86 +15,54 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
|
||||
class SQLLoginService extends AbstractController
|
||||
{
|
||||
private SQLLoginRequest $sqlLoginRequest;
|
||||
private PDO $pdo;
|
||||
|
||||
public function __construct(SQLLoginRequest $sqlLoginRequest, private LoggerInterface $loggerInterface)
|
||||
{
|
||||
public function __construct(
|
||||
private SQLLoginRequest $sqlLoginRequest,
|
||||
private LoggerInterface $loggerInterface
|
||||
) {
|
||||
$this->sqlLoginRequest = $sqlLoginRequest;
|
||||
$this->loggerInterface = $loggerInterface;
|
||||
$this->pdo = $this->getConnection();
|
||||
}
|
||||
|
||||
public function fetchDatas(string $login): array
|
||||
public function fetchPasswordAndDatas(string $login): array
|
||||
{
|
||||
if (empty($login)) {
|
||||
throw new Exception('Connexion échouée, le login ne peut pas être vide');
|
||||
}
|
||||
try {
|
||||
$dbh = $this->getConnection();
|
||||
} catch (PDOException $e) {
|
||||
$this->loggerInterface->critical($e->getMessage());
|
||||
throw new DatabaseConnectionException($e->getMessage());
|
||||
}
|
||||
try {
|
||||
// forge de la requête
|
||||
$request = $this->sqlLoginRequest->getRequestScope();
|
||||
$dataRequest = $this->sqlLoginRequest->getDatasRequest();
|
||||
$datas = $this->executeRequestWithLogin($dataRequest, $login);
|
||||
} catch (NullDataToFetchException $e) {
|
||||
throw new DataToFetchConfigurationException($e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
// Préparation de la requête
|
||||
$query = $dbh->prepare($request);
|
||||
$query->execute([$this->sqlLoginRequest->getLoginColumnName() => $login]);
|
||||
$datas = $query->fetch(PDO::FETCH_ASSOC);
|
||||
$query->closeCursor();
|
||||
} catch (PDOException $e) {
|
||||
$this->loggerInterface->critical($e->getMessage());
|
||||
throw new DataToFetchConfigurationException($e->getMessage());
|
||||
}
|
||||
|
||||
if (false === $datas) {
|
||||
throw new Exception(sprintf('La requête sql "%s" a renvoyé un résultat incorrect.', $request));
|
||||
throw new LoginElementsConfigurationException($e->getMessage());
|
||||
}
|
||||
|
||||
return $datas;
|
||||
}
|
||||
|
||||
public function fetchPassword(string $login): array
|
||||
private function executeRequestWithLogin(string $request, string $login): array
|
||||
{
|
||||
try {
|
||||
$dbh = $this->getConnection();
|
||||
} catch (PDOException $e) {
|
||||
$this->loggerInterface->critical($e->getMessage());
|
||||
throw new DatabaseConnectionException($e->getMessage());
|
||||
}
|
||||
$query = $this->pdo->prepare($request);
|
||||
$query->bindParam($this->sqlLoginRequest->getLoginColumnName(), $login, PDO::PARAM_STR);
|
||||
$query->execute();
|
||||
$datas = $query->fetch(PDO::FETCH_ASSOC);
|
||||
$query->closeCursor();
|
||||
|
||||
// forge de la requête
|
||||
$request = $this->sqlLoginRequest->getRequestPassword();
|
||||
|
||||
try {
|
||||
$query = $dbh->prepare($request);
|
||||
$query->execute([$this->sqlLoginRequest->getLoginColumnName() => $login]);
|
||||
$password = $query->fetch(PDO::FETCH_ASSOC);
|
||||
$query->closeCursor();
|
||||
} catch (PDOException $e) {
|
||||
$this->loggerInterface->critical($e->getMessage());
|
||||
throw new LoginElementsConfigurationException($e->getMessage());
|
||||
}
|
||||
if (!$password) {
|
||||
throw new Exception('Une erreur est survenue lors de la récupération des données');
|
||||
}
|
||||
|
||||
return [
|
||||
$password[$this->sqlLoginRequest->getPasswordColumnName()],
|
||||
isset($password[$this->sqlLoginRequest->getSaltColumnName()]) ? $password[$this->sqlLoginRequest->getSaltColumnName()] : null,
|
||||
];
|
||||
return $datas;
|
||||
}
|
||||
|
||||
private function getConnection(): PDO
|
||||
{
|
||||
// Appel du singleton
|
||||
$sqlLogin = SQLLoginConnect::getInstance();
|
||||
// Connection bdd
|
||||
return $sqlLogin->connect($this->sqlLoginRequest->getDatabaseDsn(), $this->sqlLoginRequest->getDbUser(), $this->sqlLoginRequest->getDbPassword());
|
||||
try {
|
||||
$sqlLogin = SQLLoginConnect::getInstance();
|
||||
$pdo = $sqlLogin->connect($this->sqlLoginRequest->getDatabaseDsn(), $this->sqlLoginRequest->getDbUser(), $this->sqlLoginRequest->getDbPassword());
|
||||
} catch (PDOException $e) {
|
||||
$this->loggerInterface->critical($e->getMessage());
|
||||
throw new DatabaseConnectionException($e->getMessage());
|
||||
}
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user