Easy2Do permet l'affichage et le téléchargement de documents de manière sécurisée. En effet, les documents sont stockés dans un espace de stockage sécurisé et ne sont pas directement accessibles via une URL publique sans les droits appropriés. Pour permettre aux utilisateurs d'afficher ou de télécharger ces documents, il est nécessaire de gérer des droits d'accès.
L'objectif de ce cookbook est de fournir une vue d'ensemble claire et des ressources pour implémenter efficacement l'affichage et le téléchargement de documents dans une application Easy2Do.
En mode web
Gestion native des droits d'accès
Par convention, dans Easy2Do, nous stockons les documents dans un dossier "data" à la racine du projet. En son sein, on crée un dossier par module et éventuellement des sous-dossiers à l'intérieur pour organiser. Sans protection particulière, n'importe qui pourrait accéder à ces documents sans être authentifié ou sans avoir les droits nécessaires. C'est pourquoi Easy2Do dispose de gardes-fous pour protéger l'accès à ces ressources.
Nous allons créer un dossier "data" à la racine de notre projet, puis un dossier du nom de notre module "commande" à l'intérieur. Ensuite, créons un sous-dossier "facture" pour y déposer un PDF de facture specimen "8".
Déjà tentons d'accéder, sans être connecté, directement au document étant donné que nous connaissons son chemin d'accès :
http://localhost:8080/data/commande/facture/8
Document introuvable. C'est normal car une règle de réécriture du .htaccess intercepte tous les appels ciblant le dossier "data" et bloque l'accès si le visiteur n'est pas authentifié.
RewriteRule ^data/(.*)$ index.php?szZone=admin&sChemin=$1&szAction=recuperation_document [QSA]
Bien sûr, une bonne pratique est de ne pas diffuser le chemin d'accès et plutôt de passer par un intermédiaire. Si tu te connectes tu verras que tu as accès au document. C'est parce que la règle de réécriture du .htaccess redirige vers une action qui vérifie les droits d'accès avant de permettre l'affichage ou le téléchargement du document.
Nous allons créer une route dédiée au contrôleur de notre module en nous appuyant sur la même action (recuperation_document) que celle utilisée pour la réécriture d'URL. Cette route permettra de faire le lien entre une URL plus conviviale et l'action qui gère la récupération du document. Elle va avoir besoin de 4 paramètres : le module, le sous dossier du dossier data dans lequel le fichier est stocké, l'id du document et le type de récupération du fichier (téléchargement ou visualisation en ligne).
html_recuperation_facture:
reecriture: 'document/([a-z-_]*)/([a-z]*)/([a-z-_0-9\.]*)/([a-z]*)-document.html'
route:
zone: admin
module: commande
controller: facture
action: recuperation_document
variables:
- sModule
- sSousDossier
- sNomFichier
- sType
bAutoriserGet: true # nécessaire pour ne pas se faire bloquer par l'API REST
Comme pour chaque modification d'un fichier YAML, il est nécessaire de faire un appel avec le paramètre bResetCache.
Ensuite, le document est visible :
http://localhost:8080/document/commande/facture/8/visualise-document.html
Ou téléchargeable :
http://localhost:8080/document/commande/facture/8/telecharge-document.html
Je t'invite à essayer en étant déconnecté pour voir que tu n'as pas accès au document. Ensuite, connecte toi et tu verras que tu as accès au document.
Maintenant, crée un sous-dossier "test" dans data/commande/facture et déplaces-y ton PDF dedans.
Pour y accéder, tu dois ajouter un paramètre à ton URL :
http://localhost:8080/document/commande/facture/8/visualise-document.html?sArborescenceInferieure=test
Ou téléchargeable :
http://localhost:8080/document/commande/facture/8/telecharge-document.html?sArborescenceInferieure=test
Gestion avancée des droits d'accès
Maintenant, nous allons voir comment gérer les droits d'accès de manière plus fine. Par exemple, nous allons voir comment interdire l'accès aux factures qui n'appartiennent pas à l'utilisateur connecté.
Nous allons créer une classe model (dans modules/commande/models) qui contiendra la méthode chargée de vérifier que la commande est bien liée à l'utilisateur connecté. Cette méthode prendra en paramètre l'id de la facture et l'id de l'utilisateur connecté.
<?php
namespace APP\Modules\Commande\Models;
use APP\Modules\Base\Lib\Bdd;
class Commande extends Bdd
{
public function bCommandeAssocieeUtilisateurCourant(int $nIdCommande): bool
{
$sRequete = <<<SQL
SELECT COUNT(numero_facture) AS nNbFacture
FROM app_commande
WHERE commande_id = :nIdCommande
AND utilisateur_id = :nIdUtilisateur
SQL;
$aParams = [
'nIdCommande' => $nIdCommande,
'nIdUtilisateur' => $_SESSION['nIdUtilisateur'] ?? 0,
];
$oRequete = $this->oPreparerRequete($sRequete);
$oRequete->execute($aParams);
return $oRequete->fetchColumn() > 0;
}
}
Ensuite, un contrôleur (dans modules/commande/controllers) appelé automatiquement par le coeur d'E2D lors de la récupération du document va faire appel à cette méthode pour vérifier que l'utilisateur connecté a bien le droit d'accéder à la facture.
<?php
namespace APP\Modules\Commande\Controllers;
use APP\Core\Lib\Interne\PHP\UndeadBrain;
class DocumentVisuCommande extends UndeadBrain
{
public function bDroitAccesDocument(object $oParams): bool
{
if (isset($oParams->nIdDocument) === false) {
die('Vous n\'avez pas accès à ce document.');
}
$nIdCommande = $oParams->nIdDocument;
$oCommande = $this->oNew('Commande');
$bCommandeAssociee = $oCommande->bCommandeAssocieeUtilisateurCourant($nIdCommande);
if ($bCommandeAssociee == 0) {
die('Vous n\'avez pas accès à ce document.');
}
return true;
}
}
Enfin, il faut bien penser à déclarer nos deux nouvelles classes dans le fichier modules/commande/config/conf.yml :
aNamespace:
data:
DocumentVisuCommande: APP\Modules\Commande\Controllers\DocumentVisuCommande
Commande: APP\Modules\Commande\Models\Commande
Prérequis web
| Élément | Version / Remarque |
|---|---|
| PHP | 8.4 |
| E2D - Core | 2.18 |
| E2D - Bdd | 3.0 |
| E2D - Auth | 1.8 |
En mode API RestFUL
Nous considérons ici que tu as suivi la partie web du cookbook et que tu as déjà un document stocké dans le dossier data/commande/facture. Seule la route html_recuperation_facture initialement déclarée dans la partie web peut être supprimée.
Ajouter la ressource RestFUL. A la racine du projet :
git submodule add -b release-1.3 git@bitbucket.org:doingfr/easy2do-restful.git ressources/restful
Créer un fichier services.yml dans le dossier config de notre module commande :
aServices:
DocumentVisu:
aMethodes:
Read:
zone: admin
module: commande
controller: facture
action: recuperation_document
bExtractPayload: true
L'appel du webservice avec les bons paramètres est présent dans le Bruno de l'exemple.
Prérequis API RestFUL
| Élément | Version / Remarque |
|---|---|
| PHP | 8.4 |
| E2D - Core | 2.18 |
| E2D - Bdd | 3.0 |
| E2D - Auth | 1.8 |
| E2D - Restful | 1.3 |
Le code complet (structure de répertoires, tests, configuration) est disponible dans le repo d’exemples Doing.
➡ Easy2Do : https://bitbucket.org/doingfr/doing-cookbooks-examples/src/main/e2d-document-visu/easy2do/
TL;DR
- Savoir télécharger ou afficher un document stocké dans Easy2Do
- Savoir appliquer des droits plus fins sur les documents