Accès aux fichiers et à la récupération
- Leçon 13
- 55 min
- Module 4 : Contrôler l'accès aux ressources
Leçon 13 sur 19 · Authentification, autorisations et applications multilocatairesAccès aux fichiers et à la récupération
1. Bases de l'identité et des autorisations
2. Comprendre la connexion et les jetons
3. Sessions et intégration à l'application
4. Contrôler l'accès aux ressources
5. Travail en arrière-plan et administration
6. Valider et documenter la conception
Ce que vous saurez faire
Gardez l’organisation liée aux données quand elles quittent les tables. Cela comprend les liens de fichiers, la recherche de billets similaires, les citations de documents et les réponses en cache. Prouvez ensuite qu’un identifiant deviné ne donne accès à rien.
Avant de commencerCe qu’il faut savoir et avoir sous la main
Ce que vous devez savoir
- Les quatre vérifications de L’autorisation dans l’API et les deux verrous de Requêtes sûres pour chaque locataire.
- Les URL signées, dans Modèles de stockage objet, et la recherche vectorielle avec un filtre, dans Stockage des vecteurs.
Votre projet
~/projects/ticket-apià l’instantanéend-of-m04. Le fournisseur, l’API et Azurite fonctionnent. Obtenez les jetons comme dans la première leçon de ce module :Ipour Ines,Spour Sam,Opour Omar,Cpour Camille.
I=$(python -m scripts.login --user usr-ines --print-access-token)Sur Windows : $I = python -m scripts.login --user usr-ines --print-access-token, et tapez curl.exe. Créez les trois autres jetons de la même façon.
Un billet de concert, une bibliothèque et un casier
Section intitulée « Un billet de concert, une bibliothèque et un casier »Trois situations courantes, une pour chaque partie de cette leçon.
Un billet de concert vous laisse entrer, peu importe qui vous êtes. Le personnel à l’entrée vérifie son authenticité et sa validité pour ce soir. Il ne vérifie pas votre nom. La billetterie doit donc décider qui reçoit un billet, car ensuite, c’est le billet qui décide.
Deux écoles partagent un catalogue de bibliothèque. Un élève de la première école cherche « chimie ». Si le catalogue ne filtre pas par école, le meilleur résultat peut être sur une tablette de l’autre école. L’élève ne peut pas emprunter ce livre.
Une salle du courrier contient des casiers portant seulement l’étiquette « réponse à la question 7 ». La première personne qui pose la question 7 reçoit une réponse. Une copie reste dans le casier. La personne suivante qui pose la question 7 reçoit cette copie, même si la bonne réponse pour elle est différente.
Chaque situation représente un endroit où les données quittent les tables protégées. L’API crée un lien de fichier, lance une recherche, cite un document et garde une réponse en cache. Chacun de ces éléments a aussi besoin de l’organisation.
Liens de fichiers : vérifier d’abord, signer ensuite
Section intitulée « Liens de fichiers : vérifier d’abord, signer ensuite »Le cours sur les bases de données conserve les fichiers dans le stockage objet. L’API distribue des URL signées : des liens avec une signature et une heure d’expiration. Le stockage vérifie seulement la signature et l’heure. Comme le billet de concert, le lien fonctionne pour toute personne qui le possède.
Que se passe-t-il si une route signe avant de vérifier? La démonstration de fuite crée volontairement cette route incorrecte :
python -m scripts.leak_demo file3. A signed download link is a key on its own (constructed: the link is made for Bramble Books' receipt, as a route would make it if it signed before checking): GET http://127.0.0.1:10000/devstoreaccount1/attachments/tickets/T-40001/e7e54964-6167-47fa-8c59-b0b14b2d7e4a/receipt-BB-310729.pdf?... (no token, no session) -> 200, 724 bytes. Whoever has the link has the file until 06:34:14 UTC.La démonstration a récupéré le reçu de Bramble sans jeton ni session : 200, 724 octets. Votre heure d’expiration diffère. Personne ne peut reprendre le lien. Il fonctionne pendant 5 minutes pour quiconque le voit dans un journal, une conversation ou un courriel transféré.
La route de téléchargement de l’API fait trois choses, dans cet ordre. Elle effectue les quatre vérifications pour file.read. Elle cherche le fichier dans l’organisation : WHERE tenant_id = %s AND attachment_id = %s. Ensuite seulement, elle signe un lien valable 5 minutes. Essayez avec le véritable identifiant du reçu de Bramble :
curl -H "Authorization: Bearer $I" http://127.0.0.1:8000/v1/tenants/bramble/attachments/e7e54964-6167-47fa-8c59-b0b14b2d7e4a/download{"url":"http://127.0.0.1:10000/devstoreaccount1/attachments/tickets/T-40001/e7e54964-6167-47fa-8c59-b0b14b2d7e4a/receipt-BB-310729.pdf?se=2026-10-10T06%3A35%3A08Z&sp=r&sv=2026-10-06&sr=b&rscd=…&sig=…","expires_at":"2026-10-10T06:35:08Z"}Ines est propriétaire, donc elle reçoit un lien. Sam connaît le même identifiant. Il fait la demande par sa propre organisation :
curl -H "Authorization: Bearer $S" http://127.0.0.1:8000/v1/tenants/larkfield/attachments/e7e54964-6167-47fa-8c59-b0b14b2d7e4a/download{"error":{"code":"not_found","message":"Attachment e7e54964-6167-47fa-8c59-b0b14b2d7e4a does not exist.","request_id":"d0f4e73a9a6c","fields":[]}}L’API ne crée aucun lien. Par bramble, il reçoit le message Not found. (introuvable) destiné aux personnes externes, comme dans la première leçon.
Description textuelle du diagramme
Ines demande un téléchargement. L’API vérifie son adhésion et son rôle. Elle cherche le fichier en incluant l’organisation de Bramble dans la requête. Ensuite seulement, elle signe un lien valable 5 minutes. Le stockage vérifie la signature et l’heure, rien d’autre. Quiconque obtient le lien peut donc télécharger les 724 octets sans jeton, par exemple depuis un courriel transféré. La demande de Sam pour le même identifiant par Larkfield n’atteint jamais l’étape de signature. La recherche ne trouve rien, et la réponse est 404.
Les nouveaux fichiers utilisent un chemin qui contient l’organisation : tenants/bramble/tickets/T-40002/<id>/photo.png. Les fichiers des données chargées gardent les chemins du cours sur les bases de données, tickets/T-40001/…. Le lien ci-dessus le montre. Le chemin ne protège rien, car la vérification se fait dans l’API. Il aide les gens : une sauvegarde, une suppression ou un audit peut porter sur le dossier d’une seule organisation.
Recherche de billets similaires : filtrer dans la même requête
Section intitulée « Recherche de billets similaires : filtrer dans la même requête »Ines demande des billets similaires à son T-40001, « Facturé deux fois pour la commande BB-310729 ». Larkfield a aussi des billets « Facturé deux fois », et leurs vecteurs sont proches. La démonstration lance la recherche vectorielle sans l’organisation, puis avec elle :
python -m scripts.leak_demo search1. Similar tickets of Bramble Books' T-40001, WITHOUT the organization filter (wrong): T-40030 0.036 bramble: Charged twice for order BB-310465 T-40007 0.037 bramble: Charged twice for order BB-310771 T-40004 0.042 bramble: Charged twice for order BB-310181 T-30050 0.048 larkfield: Charged twice for order LK-710804 T-30076 0.051 larkfield: Charged twice for order LK-140806 WITH the filter (the API's code): T-40030 0.036 bramble: Charged twice for order BB-310465 T-40007 0.037 bramble: Charged twice for order BB-310771 T-40004 0.042 bramble: Charged twice for order BB-310181 T-40002 0.061 bramble: Charged twice for my book order T-40034 0.068 bramble: Charged twice for my book orderLes nombres sont des distances : une valeur plus petite indique un sens plus proche. Sans filtre, 2 des 5 résultats appartiennent à Larkfield. Leurs distances sont 0,048 et 0,051. Une page de soutien affichant des billets similaires montrerait à Ines la commande d’un client de Larkfield. Avec le filtre, les quatrième et cinquième places reviennent aux billets de Bramble, dont les vecteurs sont un peu plus éloignés.
Le filtre fait partie de la même instruction SQL que la recherche : e.tenant_id = %(tenant_id)s. Il accompagne les filtres d’équipe et de statut du cours sur les bases de données. Ne filtrez pas ensuite dans Python. Une recherche de 5 résultats qui en élimine 2 n’en renvoie que 3. L’index approximatif (HNSW) trouve des candidats de toutes les organisations. Le balayage itératif de pgvector poursuit alors la lecture jusqu’à ce que 5 lignes passent le filtre. Par l’API, Ines obtient les cinq billets de Bramble :
curl -H "Authorization: Bearer $I" "http://127.0.0.1:8000/v1/tenants/bramble/tickets/T-40001/similar?k=5"Les valeurs de ticket_id sont T-40030, T-40007, T-40004, T-40002 et T-40034.
Documents et citations : l’organisation et le niveau d’accès
Section intitulée « Documents et citations : l’organisation et le niveau d’accès »Les documents d’aide ont deux autorisations. Chaque document appartient à une organisation. Certains sont aussi réservés au personnel, comme les limites d’approbation des remboursements de Larkfield. La route GET /v1/tenants/{tenant}/documents?q= les recherche et renvoie chaque résultat avec son doc_id et sa version. Ces deux valeurs forment une citation : une référence qu’une personne ou un assistant d’IA peut citer, et qu’un lecteur peut ouvrir.
Cherchez « refund approval » (approbation de remboursement) en tant qu’Omar, puis en tant que Sam :
curl -H "Authorization: Bearer $O" "http://127.0.0.1:8000/v1/tenants/larkfield/documents?q=refund%20approval"curl -H "Authorization: Bearer $S" "http://127.0.0.1:8000/v1/tenants/larkfield/documents?q=refund%20approval"Les réponses sont longues. Voici donc leurs citations :
| Appelant | access_level |
Résultats (doc_id, version, accès) |
|---|---|---|
| Omar, read_only | public | returns-policy v4 public, refunds-and-payments v3 public |
| Sam, staff | staff | refund-approval-procedure v2 staff, returns-policy v4 public, refunds-and-payments v3 public, warranty-claims-procedure v3 staff |
La réponse d’Omar ne contient aucun document réservé au personnel, donc elle ne peut pas en citer. C’est plus important qu’il n’y paraît. Un assistant d’IA qui rédige une réponse à partir de ces résultats ne peut citer que ce que l’appelant peut ouvrir. Imaginez que la recherche renvoie la procédure réservée au personnel. L’assistant pourrait alors divulguer « un agent peut approuver jusqu’à 100 dollars » dans une phrase, sans aucun lien.
Les deux boutiques ont un document nommé returns-policy. L’organisation fait partie de la clé du document, donc ils ne se mélangent jamais. Ines cherche « returns » (retours) et obtient la version 1 du document returns-policy de Bramble, « Retourner un livre ». Elle n’obtient jamais la version 4 de Larkfield.
Clés de cache : tout ce qui change la réponse
Section intitulée « Clés de cache : tout ce qui change la réponse »L’API garde les réponses des recherches de billets similaires et de documents pendant 60 secondes (CACHE_SECONDS). Une réponse en cache évite la requête, et donc son filtre. La clé de cache, l’étiquette sous laquelle une réponse est conservée, doit donc contenir tout ce qui change la réponse.
La démonstration crée volontairement deux caches incorrects :
python -m scripts.leak_demo cache2a. A cache key without the organization (wrong): key = ('similar', ticket, k) Ines gets: ['T-30050 Charged twice for order LK-710804', 'T-30168 Charged twice for order LK-919420', 'T-30064 Charged twice for order LK-167846'] With the organization in the key, Ines's key misses: None2b. A key without the access level (wrong): Sam (staff) asks first, then Omar Omar (read-only) gets: [('refund-approval-procedure', 'staff'), ('returns-policy', 'public'), ('refunds-and-payments', 'public'), ('warranty-claims-procedure', 'staff')]Dans 2a, Grace demande des billets similaires à T-30002. Sa réponse est conservée sous ('similar', 'T-30002', 3). Ines demande ensuite le même identifiant de billet par Bramble Books. Elle passe la vérification d’adhésion à sa propre organisation. Le cache répond avant l’exécution de la requête, et elle obtient les trois billets de Larkfield. Dans 2b, Omar obtient la réponse de Sam destinée au personnel, avec deux documents réservés au personnel.
Description textuelle du diagramme
Sans organisation dans la clé, la réponse de Grace et la question d’Ines partagent une clé. Ines obtient donc les billets de Larkfield. Avec l’organisation en premier, ce sont deux clés. La recherche d’Ines ne trouve rien en cache, et sa requête s’exécute dans Bramble Books. La recherche de documents ajoute le niveau d’accès à sa clé. La réponse du personnel reste donc séparée de la réponse publique.
Le fichier ticket_api/cache.py du projet crée chaque clé avec une seule fonction :
def cache_key(tenant_id: str, name: str, *parts) -> tuple: if not tenant_id: raise ValueError("a cache key of an organization's data needs the organization") return (tenant_id, name, *parts)La route des billets similaires appelle cache_key(caller.tenant_id, "similar", ticket_id, k, team, status, version). La route des documents appelle cache_key(caller.tenant_id, "documents", level, q.lower()). Ici, level vaut staff (personnel) ou public, selon le rôle de l’appelant. Deux autres règles accompagnent le cache. Le cache vient après les quatre vérifications. Une personne qui perd son accès reçoit donc 404, même si une réponse est encore en cache. Chaque réponse ne reste que 60 secondes.
Ce cache se trouve dans un seul processus de l’API. Un cache partagé, comme Redis, suit la même règle pour les clés. Le cours Mise à l’échelle des API et des charges de travail d’IA en ajoute un.
Le parcours complet d’une autorisation
Section intitulée « Le parcours complet d’une autorisation »Voici tout le module en une image. L’autorisation commence dans la requête et doit atteindre chaque endroit d’où proviennent les données.
Description textuelle du diagramme
Une requête nomme l’organisation dans son chemin. L’API vérifie l’identité, l’adhésion, le rôle et la portée, puis crée un appelant vérifié : Ines, Bramble Books, propriétaire. Cet appelant accompagne cinq endroits. Les requêtes sur les lignes incluent tenant_id et la sécurité au niveau des lignes. La route des fichiers cherche le fichier dans l’organisation avant de signer un lien. La recherche vectorielle filtre par organisation dans la même requête. La recherche de documents utilise l’organisation et le niveau d’accès. La clé de cache commence par l’organisation. Sous chaque endroit figure la fuite observée dans le cours sans cette protection. La liste contenait 77 billets de Larkfield sur 100. Le reçu s’ouvrait pour quiconque possédait le lien. Deux billets similaires sur cinq provenaient de Larkfield. Omar obtenait deux documents réservés au personnel. Une entrée de cache partagée donnait à Ines les billets de Larkfield.
À vous : essayez de franchir la limite
Section intitulée « À vous : essayez de franchir la limite »Vous avez vu les exemples détaillés. Attaquez maintenant votre propre API d’exercice en tant que Camille et Omar, avec des enregistrements inventés. Prédisez chaque réponse avant d’envoyer la requête.
-
Camille fait partie du personnel de Larkfield et connaît l’identifiant du reçu de Bramble. Faites la demande par Larkfield :
Fenêtre de terminal curl -H "Authorization: Bearer $C" http://127.0.0.1:8000/v1/tenants/larkfield/attachments/e7e54964-6167-47fa-8c59-b0b14b2d7e4a/downloadRésultat attendu :
404,Attachment e7e54964-… does not exist.(la pièce jointe e7e54964-… n’existe pas). Parbramble, Camille a un accès en lecture seule et obtient un lien, carread_onlypeut utiliserfile.read. -
Camille écrit un message sur le billet
T-40001de Bramble par Larkfield, où Camille fait partie du personnel. Résultat attendu :404. Ce rôle de personnel s’applique à Larkfield, etT-40001n’y existe pas. -
Omar téléverse un fichier vers le billet
T-30002de Larkfield :Fenêtre de terminal curl -X POST -H "Authorization: Bearer $O" -H "Content-Type: application/json" -d '{"file_name": "photo.png", "content_type": "image/png", "size_bytes": 1200}' http://127.0.0.1:8000/v1/tenants/larkfield/tickets/T-30002/attachmentsRésultat attendu :
403,Your role may not do this (read_only may not file.upload).(votre rôle ne permet pas cette action; read_only ne permet pas file.upload). L’API ne crée aucun lien de téléversement. -
Camille cherche « wholesale price » (prix de gros) dans les documents de Bramble. Ines obtient
supplier-terms, « Conditions de vente en gros (personnel seulement) ». Prédisez d’abord la réponse de Camille : Camille fait partie du personnel de Larkfield.Résultat attendu :
{"access_level":"public","results":[]}. Le niveau d’accès vient du rôle dans cette organisation, et chez Bramble Books, Camille a un accès en lecture seule.
Quand l’utiliser, et ce que cela coûte
Section intitulée « Quand l’utiliser, et ce que cela coûte »Appliquez ces règles partout où les données quittent la base de données : fichiers, index de recherche, caches, exportations et requêtes d’IA. Le coût est faible. Un lien de fichier attend une recherche supplémentaire. La recherche vectorielle lit quelques candidats de plus. Un cache garde une entrée par organisation et niveau d’accès, donc il trouve moins souvent une réponse. C’est le bon compromis : une absence en cache coûte des millisecondes, et une fuite coûte la confiance d’un client.
Une expiration rapide du lien a aussi un coût. Une personne avec une connexion lente peut avoir besoin d’un nouveau lien. Cinq minutes suffisent pour commencer un téléchargement. C’est aussi assez court pour qu’un lien divulgué cesse rapidement de fonctionner.
Erreurs courantes
Section intitulée « Erreurs courantes »Erreur courante
Le lien de téléchargement cesse de fonctionner après quelques minutes
Symptôme : un lien qui fonctionnait reçoit maintenant une erreur du stockage au lieu du fichier. L’auteur a demandé le lien d’Ines à 7 h 32 min 00 s UTC. curl l’a récupéré aussitôt : 200 724. L’auteur a conservé le url de la réponse de l’API dans URL. Il a récupéré le même lien à 7 h 37 min 06 s (vos heures diffèrent; sous Windows, tapez curl.exe) :
curl -s -w '\n%{http_code}\n' "$URL"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Error> <Code>AuthorizationFailure</Code> <Message>Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature.RequestId:2a19621e-…Time:2026-10-10T07:37:06.469Z</Message></Error>403Cause : le lien a expiré à 7 h 37 min 00 s (expires_at dans la réponse de l’API). C’est voulu : il dure 5 minutes. Le message parle d’un en-tête, mais la requête n’en avait aucun. Seule l’heure d’expiration du lien était passée. Cette réponse vient d’Azurite; le vrai service Azure Storage pourrait la formuler autrement (non testé).
Solution : demandez un nouveau lien à l’API. L’API refait les vérifications. Une personne qui a perdu l’accès reçoit donc 404 au lieu d’un lien. Pendant la même exécution, Ines a refait la demande à 7 h 37 min 06 s. Elle a reçu un nouveau lien, "expires_at":"2026-10-10T07:42:06Z", et curl l’a récupéré : 200 724.
Erreur courante
Moins de billets semblables que demandé
Symptôme : une recherche de 5 billets de soutien semblables en renvoie 3. Pourtant, l’organisation a plus de billets de ce type.
Cause : un filtre a été appliqué après la recherche. La recherche a trouvé 5 voisins, puis le code a éliminé ceux d’une autre organisation.
Solution : ajoutez l’organisation à la même instruction SQL que la recherche vectorielle, comme le fait repository.similar_tickets. La base de données poursuit alors la lecture jusqu’à ce qu’assez de lignes passent le filtre.
Erreur courante
Une clé de cache construite à la main
Symptôme : une nouvelle route avec cache fonctionne dans tous les tests avec une seule boutique. Avec deux boutiques, une personne voit parfois la réponse d’une autre organisation, mais seulement pendant les 60 secondes du cache.
Cause : la clé était un tuple construit à la main, comme ("export", ticket_id), sans organisation.
Solution : construisez chaque clé avec cache_key(caller.tenant_id, …). Ajoutez le niveau d’accès quand le rôle change la réponse. cache_key("", …) déclenche ValueError. L’absence d’organisation provoque donc une erreur visible.
Réinitialisation. Les démonstrations ne changent rien. L’API refuse l’étape 3, donc elle n’ajoute rien. Si vous avez téléversé vos propres fichiers, exécutez python -m scripts.load --reset.
Vérification des connaissances
Section intitulée « Vérification des connaissances »Vérifiez votre compréhension
Expliquez pourquoi l'API doit vérifier l'appelant avant de signer un lien de téléchargement, pas seulement lors de son utilisation.
Afficher la réponse
Le stockage vérifie seulement la signature et l’heure d’expiration d’un lien, pas la personne. Une fois le lien signé par l’API, toute personne qui le possède peut télécharger le fichier jusqu’à son expiration, sans jeton. La démonstration a récupéré le reçu de Bramble sans jeton : 200, 724 octets. Il faut donc décider avant de signer : les quatre vérifications, puis une recherche du fichier dans l’organisation.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Prédisez : la clé de cache de la route des documents est (locataire, 'documents', niveau, requête). Omar cherche 'refund approval' (approbation de remboursement) dans les documents de Larkfield, 10 secondes après Sam. Omar trouve-t-il une réponse en cache? Que reçoit-il?
Afficher la réponse
Non. La réponse de Sam se trouve sous ('larkfield', 'documents', 'staff', 'refund approval'). Omar a un accès en lecture seule. Sa clé est donc ('larkfield', 'documents', 'public', 'refund approval'). L’API exécute sa recherche et renvoie 2 documents publics, returns-policy et refunds-and-payments.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Vérification du module : prouvez que l'accès est refusé même si quelqu'un devine un identifiant d'enregistrement valide. Utilisez un vrai identifiant de billet et un vrai identifiant de pièce jointe de Bramble Books, avec le jeton de Sam. Quelles requêtes envoyez-vous, que répond chacune et quels tests vérifient la même chose?
Afficher la réponse
Les identifiants T-40001 et e7e54964-6167-47fa-8c59-b0b14b2d7e4a correspondent à de vrais enregistrements de Bramble.
GET /v1/tenants/larkfield/tickets/T-40001: 404, « Ticket T-40001 does not exist. » (le billet T-40001 n’existe pas), comme pour le billet absentT-49999.GET /v1/tenants/bramble/tickets/T-40001: 404, « Not found. » (introuvable), comme pour une organisation inventée.GET /v1/tenants/larkfield/attachments/e7e54964-…/download: 404, « Attachment … does not exist. » (la pièce jointe … n’existe pas), et l’API ne crée aucun lien.python -m scripts.attemptsse termine par0 of 10 attempts got what they should not get.(0 tentative sur 10 a obtenu un accès interdit).python -m pytest tests/test_access_control.py tests/test_tenant_queries.py tests/test_row_security.pyréussit 25 tests, donttest_another_organizations_ticket_looks_like_a_ticket_that_does_not_exist. La base de données ajoute une deuxième preuve. Avecticket_apppour Larkfield,SELECT count(*) FROM tickets WHERE ticket_id = 'T-40001'vaut 0.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Récapitulatif
- Un lien signé fonctionne pour n’importe qui jusqu’à son expiration. L’API vérifie donc l’appelant et trouve le fichier dans l’organisation avant de signer. Les nouveaux fichiers vont sous
tenants/<organization>/. - La recherche de billets semblables filtre par organisation dans la même instruction SQL. Sans ce filtre, 2 des 5 résultats pour
T-40001de Bramble appartenaient à Larkfield. - Les résultats de documents contiennent l’organisation et le niveau d’accès. Leurs citations (
doc_id,version) pointent seulement vers des documents que l’appelant peut ouvrir. - Une clé de cache contient tout ce qui change la réponse : l’organisation, le niveau d’accès, puis la requête. Le cache vient après les vérifications.
Récapitulatif du module. Chaque route se trouve sous son organisation et effectue quatre vérifications : identité, adhésion, rôle et portée, puis enregistrement dans l’organisation. Les personnes externes reçoivent le même code 404 pour les organisations réelles et inventées; les membres reçoivent 403. Chaque requête exige l’organisation comme argument, et la sécurité au niveau des lignes forme un deuxième verrou. Les fichiers, la recherche, les citations et les caches contiennent aussi l’organisation. scripts.attempts : 0 sur 10. Votre projet correspond à end-of-m04.
Ensuite, le travail exécuté plus tard : les tâches en arrière-plan doivent retenir qui a fait la demande et pour quelle organisation. Elles doivent revérifier les deux lors de leur exécution.
Leçon suivante : Contexte d'identité des tâches