Trois questions distinctes
- Leçon 1
- 45 min
- Module 1 : Bases de l'identité et des autorisations
Leçon 1 sur 19 · Authentification, autorisations et applications multilocatairesTrois questions distinctes
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
Posez trois questions distinctes pour chaque requête à l’API de billets de soutien : qui appelle, dans quelle organisation et que peut cette personne y faire? Préparez le projet du cours. Vous verrez que sa seule clé partagée ne répond bien à aucune de ces questions.
Avant de commencerCe qu’il faut savoir et avoir sous la main
Ce que vous devez savoir
- L’API de billets et sa clé d’API dans l’en-tête
X-API-Key, présentées dans Protection de base du cours Créer et déployer votre première API. - Le projet de Bases de données et stockage pour les applications d’IA : PostgreSQL dans Docker, les migrations,
python -m scripts.loadetpsql. Ce cours part de sa dernière version. - Un terminal,
cdet un environnement virtuel.
Ce qu’il vous faut sur votre ordinateur
- Python 3.12 ou une version ultérieure, et Docker Desktop, comme dans le cours sur les bases de données. Installer et vérifier dans le cours sur Docker présente l’installation de Docker.
- Environ 2 Go d’espace disque libre. Aucun compte, aucune clé et rien à payer.
Vous créez un nouveau dossier de projet, ~/projects/ticket-api, à partir de l’instantané start. C’est le projet du cours sur les bases de données à sa fin, sans aucun changement.
Un code de porte n’est pas une carte d’identité
Section intitulée « Un code de porte n’est pas une carte d’identité »Imaginez un immeuble de bureaux avec un seul code de porte. Toutes les personnes qui y travaillent connaissent le code. La porte s’ouvre pour quiconque le tape.
Le code fonctionne bien tant qu’une petite entreprise occupe l’immeuble. Puis une deuxième entreprise loue le deuxième étage. Le code présente maintenant trois problèmes. La porte ne peut pas dire qui est entré : le personnel d’entretien, le gestionnaire et les visiteurs tapent les mêmes chiffres. Elle ne peut pas dire quelle entreprise la personne visite. Et elle ne peut pas dire ce que cette personne peut faire à l’intérieur : le code ouvre toutes les pièces, à chaque étage.
Un bon service d’accueil pose plutôt trois questions distinctes. Qui êtes-vous? Montrez votre carte. Quelle entreprise visitez-vous? Votre nom figure-t-il sur sa liste? Que pouvez-vous y faire? Un visiteur peut s’asseoir dans la salle de réunion, mais pas ouvrir la caisse.
L’API de billets a un code de porte. Dans cette leçon, vous voyez exactement à quelles questions il peut répondre, et ses limites.
Larkfield accueille un deuxième commerce
Section intitulée « Larkfield accueille un deuxième commerce »Vous connaissez le service de soutien de Larkfield grâce aux cours précédents. Grace dirige les agents de soutien, et Sam répond aux billets. Omar, le gestionnaire de produit, lit les billets pour planifier les prochaines fonctionnalités. Amira développe l’API de billets. Tomás est un ingénieur en IA qui aime les raccourcis.
Larkfield offre maintenant son service de soutien à un deuxième commerce, Bramble Books, une librairie indépendante. Sa propriétaire est Ines. Bramble Books conservera ses clients, ses billets et ses fichiers dans la même API et la même base de données. Camille, une personne d’expérience dans l’équipe de soutien de Larkfield, aidera Ines pendant ses premières semaines.
Kwame rejoint l’équipe comme architecte de solutions. Il guide la conception dans ce cours. Avant tout code, il pose ces questions pour chaque requête : « Qui appelle, que peut cette personne faire et dans quelle organisation? »
Préparer le projet
Section intitulée « Préparer le projet »Le projet est ticket-api, tel qu’il était à la fin du cours sur les bases de données. Si vous avez terminé ce cours, votre dossier est identique à start. Faites quand même une nouvelle copie. Ce cours le modifie étape par étape, et les leçons supposent que vous avez les mêmes fichiers.
-
Obtenez les fichiers du cours. Si vous avez cloné le dépôt des exercices pour un cours précédent, mettez-le à jour dans
~/projects:Fenêtre de terminal cd ~/projects/nextia-learning-labsgit pullcd ..Si vous ne l’avez pas encore, clonez-le dans
~/projectsavecgit clone https://github.com/Nextia-Intelligence/nextia-learning-labs.git. Sans Git, téléchargez le fichier ZIP et décompressez-le dans~/projects. -
Si un dossier
ticket-apiexiste déjà, venant du cours sur les bases de données, arrêtez d’abord ses conteneurs. Supprimez aussi leurs données. Docker nomme les conteneurs et les volumes de données d’après le dossier. Votre nouveau dossier porte le même nom. Il réutiliserait donc l’ancienne base de données, avec son ancien mot de passe et ses anciennes données :Fenêtre de terminal cd ticket-apidocker compose down --volumescd ..Vos anciens fichiers restent, et vous pouvez recharger les données du cours à tout moment. Renommez ensuite l’ancien dossier, par exemple en
ticket-api-databases. Copiez l’instantanéstart, ouvrez ce dossier dans le terminal et créez votre.env:Fenêtre de terminal cp -R nextia-learning-labs/C23/snapshots/start ticket-apicd ticket-apicp .env.example .envFenêtre de terminal Copy-Item -Recurse nextia-learning-labs\C23\snapshots\start ticket-apicd ticket-apiCopy-Item .env.example .env -
Ouvrez le dossier dans VS Code. Dans
.env, remplacezchange-me-local-onlypar votre propre mot de passe, aux trois endroits. -
Démarrez Docker Desktop. Démarrez ensuite PostgreSQL et Azurite, le stockage objet pour les fichiers :
Fenêtre de terminal docker compose up -d db azuriteExécutez
docker compose psjusqu’à ce que la lignedbindique(healthy)(en bon état). -
Créez l’environnement virtuel et installez les paquets :
Fenêtre de terminal python3 -m venv .venvsource .venv/bin/activatepython -m pip install -r requirements.txtFenêtre de terminal python -m venv .venv.venv\Scripts\Activate.ps1python -m pip install -r requirements.txt -
Chargez les données :
Fenêtre de terminal python -m scripts.loadapplied 001_create_classificationsapplied 002_add_score…applied 012_erasureDatabase is up to date (12 migrations).Loaded the small data in 1.9 s:customers 40tickets 200messages 331attachments 43documents 36ai_runs 294ticket_embeddings 20043 files uploaded to the object storage.3 messages have no ticket: they are in orphaned_messages.Les lignes 003 à 011 sont omises ici. Les douze migrations viennent du cours sur les bases de données. Votre durée sera différente.
-
Exécutez les tests :
Fenêtre de terminal python -m pytestLa dernière ligne est
108 passed, 1 deselected(108 tests réussis, 1 non sélectionné). Le test non sélectionné exige Azurite et s’exécute seulement avec-m azurite, comme dans le cours sur les bases de données.
Si vous voyez ces deux résultats, votre installation fonctionne. Chaque étape du cours a été testée sur macOS (puce Apple). Les commandes pour Windows et Linux sont fournies, mais n’ont pas été exécutées.
Poser les trois questions à l’API
Section intitulée « Poser les trois questions à l’API »Posez maintenant les trois questions de Kwame à l’API elle-même. Démarrez-la avec une clé d’API, comme dans le cours sur les API. Ouvrez un deuxième terminal dans le dossier du projet, activez l’environnement virtuel et exécutez :
API_KEY=local-dev-key fastapi dev$env:API_KEY = "local-dev-key"fastapi devDans le premier terminal, demandez le billet T-30002 sans la clé. Sous Windows, tapez curl.exe plutôt que curl :
curl -i http://127.0.0.1:8000/v1/tickets/T-30002HTTP/1.1 401 Unauthorizedcontent-type: application/jsonx-request-id: 7bbff66891b8
{"error":{"code":"unauthorized","message":"A valid X-API-Key header is required.","request_id":"7bbff66891b8","fields":[]}}Certains en-têtes sont omis. Envoyez la même requête avec la clé :
curl -H "X-API-Key: local-dev-key" http://127.0.0.1:8000/v1/tickets/T-30002{"ticket_id":"T-30002","customer_id":"C-0022","customer_name":"Hugo Garcia", "subject":"Charged twice for order LK-182074","team":"billing","priority":1,"status":"open", "message_count":1,"messages":[{"message_id":2,"author":"agent","body":"Could you send the receipt …"}], …}La réponse est abrégée ici. Ajoutez maintenant un message au billet, comme le fait un agent :
curl -X POST -H "X-API-Key: local-dev-key" -H "Content-Type: application/json" -d '{"author": "agent", "body": "We refunded one payment."}' http://127.0.0.1:8000/v1/tickets/T-30002/messages{"message_id":332,"author":"agent","body":"We refunded one payment.","created_at":"2026-10-10T06:09:21.800162Z"}Dans PowerShell, les guillemets à l’intérieur d’une chaîne fonctionnent différemment. Placez le corps dans un fichier, msg.json, et envoyez-le avec -d "@msg.json".
Regardez le terminal de l’API. L’API a écrit une ligne pour chaque requête :
INFO ticket_api: GET /v1/tickets/T-30002 401 10ms queries=0 id=7bbff66891b8INFO ticket_api: GET /v1/tickets/T-30002 200 27ms queries=3 id=3b9d4f4fea83INFO ticket_api: POST /v1/tickets/T-30002/messages 201 11ms queries=3 id=89aa010fe214Posez maintenant les trois questions pour la dernière requête.
Qui a écrit le message? Le journal indique POST, le chemin, 201, une durée et un identifiant de requête. La ligne de la base de données indique author: agent (auteur : agent). Grace, Sam et Omar envoient tous la même clé. La requête est donc identique, octet pour octet, peu importe qui l’envoie.
Description textuelle du diagramme
Grace, Sam et Omar envoient chacun POST /v1/tickets/T-30002/messages avec l’en-tête X-API-Key: local-dev-key. L’API compare la clé à celle de sa configuration. Elles correspondent, donc elle enregistre le message et répond 201 Created (créé). Elle enregistre une ligne de journal et un message dont l’auteur est « agent ». Rien dans la requête ou dans les données enregistrées ne nomme la personne.
Dans quelle organisation? La question n’a pas encore de réponse. Il n’y a qu’un commerce, donc l’API n’a aucune notion d’« organisation ». Regardez dans psql : docker compose exec db psql -U tickets -d tickets, puis \d tickets. La table contient ticket_id, customer_id, subject et dix autres colonnes. Aucune colonne n’indique à quel commerce appartient un billet.
Que peut faire la personne qui appelle? Tout ce que la clé permet. Omar a seulement besoin de lire les billets. Avec la clé, il peut aussi écrire des messages, téléverser des fichiers et lire tous les billets. L’API ne peut pas lui accorder moins de droits, car elle ne sait pas que c’est Omar qui appelle.
Tapez \q pour quitter psql. Arrêtez l’API avec Ctrl+C.
L’idée : trois questions distinctes
Section intitulée « L’idée : trois questions distinctes »Kwame écrit les trois questions au tableau. Chacune porte un nom.
L’authentification répond à « Qui appelle? » La personne prouve son identité, et l’API vérifie cette preuve. Une clé partagée prouve seulement que « la personne qui appelle a la clé ». À partir du module 2, une personne se connecte, et l’API reçoit un identifiant d’utilisateur. C’est un nom stable pour cette personne, comme usr-sam.
Le locataire répond à « Dans quelle organisation? » Un locataire est une organisation cliente dont les données se trouvent dans une application partagée. Le mot vient des immeubles : plusieurs locataires y louent de l’espace, et chacun garde ses propres pièces. Larkfield et Bramble Books sont les deux locataires de l’API de billets. « Multilocataire » signifie qu’une seule application en sert plusieurs.
L’autorisation répond à « Que peut cette personne y faire? » L’API vérifie si cette personne peut effectuer cette action dans cette organisation. L’authentification vient d’abord : vous ne pouvez pas décider ce qu’une personne peut faire avant de connaître son identité.
Description textuelle du diagramme
Les trois questions, dans l’ordre où l’API les pose. Premièrement, qui appelle : l’authentification. Deuxièmement, dans quelle organisation : le locataire. Troisièmement, que peut cette personne y faire : l’autorisation. L’API actuelle répond « quelqu’un qui a la clé », « aucune réponse » et « tout ». À la fin du cours, la première réponse est « usr-sam, d’après un jeton vérifié ». La deuxième est « larkfield : le chemin la nomme, et Sam en est membre ». La troisième réponse est « staff : lire et modifier les billets, téléverser des fichiers ».
Sam pose la question évidente : « Pourquoi trois? Pourquoi pas une seule vérification : “Sam peut-il faire ça?” »
Kwame montre le nom de Camille sur le plan. Camille fait partie du personnel de Larkfield et peut donc lire les billets de Larkfield et y répondre. Chez Bramble Books, Camille aide seulement Ines et peut donc lire, mais rien modifier. La même personne obtient deux réponses différentes à « Que peut cette personne faire? » La réponse dépend de l’organisation. L’API doit donc demander « dans quelle organisation? » avant « que peut cette personne faire? » C’est pourquoi le schéma numérote les questions dans cet ordre.
Tomás a déjà un raccourci : « Le navigateur sait pour quel commerce la personne travaille. Il peut envoyer l’identifiant du commerce dans un en-tête. » Kwame secoue la tête. Une personne peut modifier tout ce que le navigateur envoie. L’API doit trouver l’organisation dans ses propres données. La requête nomme une organisation, et l’API vérifie que la personne qui appelle en est membre. Vous construisez cette vérification au module 4.
Les réponses de la clé partagée, et ses limites
Section intitulée « Les réponses de la clé partagée, et ses limites »| Question | L’API de départ | Pourquoi cela ne suffit pas pour deux commerces |
|---|---|---|
| Qui appelle? | « Quelqu’un qui a la clé. » | Chaque personne et chaque programme ont la même clé. Un journal ne peut pas montrer qui a fait quoi. |
| Dans quelle organisation? | Aucune réponse. | Les billets de Bramble seront à côté de ceux de Larkfield, et rien ne les sépare. |
| Que peut cette personne faire? | Tout ce que la clé permet. | Omar peut seulement lire, mais la clé lui permet d’écrire. |
La clé n’est pas un mauvais choix. C’est le bon outil pour une autre question. Le cours sur les API l’utilisait pour un programme qui en appelle un autre : une vérification entre services. La question est alors « Est-ce l’un de nos programmes? », et une clé y répond bien. À la fin de ce cours, la clé protège encore /v1/classify et /v1/history, que d’autres programmes appellent. Chaque route utilisée par une personne passe à des utilisateurs connectés.
Les personnes ont besoin de plus. Chacune a besoin de sa propre identité, d’une liste de ses organisations et d’un rôle dans chacune. Cela demande un vrai travail, et ce cours le fait une étape à la fois. Vous ajoutez un fournisseur d’identité, qui connecte les personnes et émet des jetons. Vous ajoutez des vérifications de jetons dans l’API, une table d’adhésions et une vérification sur chaque route. Ensuite, vous écrivez des tests qui essaient chaque route avec chaque personne.
Dans la prochaine leçon, vous construisez les données qui répondent aux deuxième et troisième questions : personnes, organisations, adhésions et rôles. Puis Exemples de menaces montre ce qui se passe mal tant que l’API n’a que la clé. Cette leçon teste cinq tentatives inventées contre votre propre API d’exercice. Les cinq obtiennent ce qu’elles ne devraient pas obtenir.
Erreurs courantes
Section intitulée « Erreurs courantes »Erreur courante
docker compose up : le port est déjà attribué
Symptôme : docker compose up -d db azurite affiche ceci, et db ne démarre pas :
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint ticket-api-db-1 (…): Bind for 127.0.0.1:5432 failed: port is already allocatedCause : un autre conteneur utilise déjà le port 5432 sur votre ordinateur. C’est généralement la base de données d’un autre dossier de projet, par exemple celle d’un autre cours.
Diagnostic : exécutez docker ps. Cherchez un conteneur avec 127.0.0.1:5432->5432/tcp. La première partie de son nom est le nom de son dossier de projet.
Solution : dans ce dossier, exécutez docker compose down. Ses données restent dans son volume. Exécutez ensuite de nouveau docker compose up -d db azurite dans ticket-api.
Erreur courante
Chaque requête avec la clé reçoit 401
Symptôme : curl -H "X-API-Key: local-dev-key" … reçoit 401 et A valid X-API-Key header is required. (un en-tête X-API-Key valide est requis).
Cause : l’API utilise une autre clé, ou le nom de l’en-tête est incorrect. Si l’API n’utilise aucune clé, une requête sans clé reçoit 200. Le terminal de l’API affiche alors API_KEY is not set: /v1/classify accepts requests without a key (API_KEY n’est pas défini : /v1/classify accepte les requêtes sans clé).
Solution : arrêtez l’API avec Ctrl+C, puis redémarrez-la avec API_KEY=local-dev-key fastapi dev (PowerShell : définissez d’abord $env:API_KEY). Vérifiez le nom de l’en-tête : X-API-Key, suivi d’un deux-points.
Réinitialisation. python -m scripts.load --reset supprime les données du service de soutien, y compris votre nouveau message, puis les recharge. docker compose down --volumes supprime toute la base de données et les fichiers. Ensuite, exécutez docker compose up -d db azurite et python -m scripts.load.
Vérification des connaissances
Section intitulée « Vérification des connaissances »Vérifiez votre compréhension
Nommez les trois questions auxquelles l'API doit répondre pour chaque requête, et le nom technique de chacune. Pourquoi l'API demande-t-elle l'organisation avant de décider ce que l'appelant peut faire?
Afficher la réponse
Qui est l’appelant? C’est l’authentification. Dans quelle organisation? C’est le locataire. Que peut-il y faire? C’est l’autorisation. L’organisation vient avant l’autorisation, car une personne peut avoir des rôles différents dans différentes organisations. Camille fait partie du personnel chez Larkfield et a un accès en lecture seule chez Bramble Books. La question « Camille peut-elle ajouter un message? » reste donc sans réponse tant que l’API ne connaît pas 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 : Omar lit seulement des billets de soutien dans son travail. Il envoie POST /v1/tickets/T-30002/messages avec X-API-Key : local-dev-key à l'API de départ. Que répond l'API, et que note la base de données sur l'auteur du message?
Afficher la réponse
201 Created (créé). La clé est valide, et l’API ne vérifie que la clé. La ligne du message indique author: agent (auteur : agent). La ligne du journal indique POST /v1/tickets/T-30002/messages 201. Aucune des deux ne nomme Omar. L’API ne peut pas lui refuser l’accès, car elle ne peut pas distinguer sa requête de celle de Sam.
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 pratique : montrez que votre projet fonctionne. Quelles commandes exécutez-vous, et que doivent-elles afficher?
Afficher la réponse
python -m scripts.load --reset se termine par les nombres d’enregistrements (customers 40, tickets 200, messages 331, attachments 43, documents 36, ai_runs 294, ticket_embeddings 200). Elle affiche aussi 43 files uploaded to the object storage. (43 fichiers téléversés vers le stockage objet). python -m pytest se termine par 108 passed, 1 deselected (108 tests réussis, 1 exclu). Pendant que API_KEY=local-dev-key fastapi dev s’exécute, curl http://127.0.0.1:8000/v1/tickets/T-30002 reçoit la réponse 401. La même requête avec -H "X-API-Key: local-dev-key" reçoit le billet.
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.
Études de cas de ce cours
À la fin du cours, vous appliquez ce que vous avez appris à un projet réaliste, des données jusqu’à la recommandation. Terminez-en au moins une pour obtenir le certificat; les autres sont facultatives.
- Auditer le contrôle d'accès d'une application multilocataire libreExécuter sur votre ordinateur une application multilocataire libre sous licence permissive, répertorier ses utilisateurs, ses organisations et ses rôles, puis tester son isolation avec la matrice d'accès du cours.
- Ajouter la connexion et les rôles à une API existanteAjouter le fournisseur d'identité fictif, la validation des jetons et les rôles à l'API de données de l'étude de cas du cours sur les API, la tester avec une matrice d'accès, puis faire correspondre la conception à un vrai fournisseur d'identité.
Récapitulatif
- Chaque requête doit répondre à trois questions : qui est l’appelant (authentification), dans quelle organisation (le locataire), et que peut-il y faire (autorisation).
- L’API demande l’organisation avant l’autorisation, car le rôle d’une personne dépend de l’organisation.
- La clé partagée de départ dit seulement « l’appelant possède la clé ». Grace, Sam et Omar envoient les mêmes octets, et l’API enregistre
author: agent. - Une clé reste un bon choix pour un programme qui en appelle un autre. Les personnes ont besoin de leur propre identité, de leurs adhésions et de leurs rôles.
- Votre projet
~/projects/ticket-apicorrespond à l’instantanéstart(départ) :108 passed, 1 deselected.
Ensuite, vous ajoutez Bramble Books, les personnes et leurs adhésions à la base de données. Vous notez aussi qui peut faire quoi.
Leçon suivante : Utilisateurs et organisations