Semaine 5
Cette semaine nous allons ajouter une couche de sécurité et d’authentification avec des tokens JWT.
Version du front : https://csharp.nouvet.fr/front5/
Authentification JWT
Référez-vous à la documentation sur l’authentification pour comprendre le fonctionnement des JWT et leur implémentation.
Résumé des étapes
- Installer le package
Microsoft.AspNetCore.Authentication.JwtBearer - Créer un service
JwtServicepour générer les tokens - Configurer la validation JWT dans
Program.cs - Protéger les routes avec
[Authorize]
Création du service JWT
Créez un nouveau fichier Services/JwtService.cs qui contiendra une méthode GenerateToken(User user) retournant un token JWT.
Le token doit contenir les claims suivants :
ClaimTypes.NameIdentifier: l’ID de l’utilisateurClaimTypes.Name: le nom d’utilisateurClaimTypes.Role: le rôle de l’utilisateur
Référez-vous à la section Générer un JWT pour l’implémentation.
Configuration dans Program.cs
Ajoutez la configuration de l’authentification JWT. Voir la section Valider un JWT.
N’oubliez pas d’ajouter le service en AddScoped dans le Program.cs.
Modification du UserController
Injection du service JWT
Injectez le JwtService dans le constructeur du contrôleur.
Modification des routes Login et Register
Les routes Login et Register doivent maintenant retourner un token en plus des informations de l’utilisateur :
var token = _jwtService.GenerateToken(user);
return Ok(new { token = token, user = UserPublic.FromUser(user) });
Ces routes doivent rester accessibles sans authentification avec [AllowAnonymous].
Protection des routes
Ajoutez [Authorize] au niveau du contrôleur. Voir la section Vérification de l’authentification.
Pour les routes sensibles réservées aux administrateurs, utilisez [Authorize(Roles = "Admin")] :
PUT /api/User/{id}DELETE /api/User/{id}
Récupérer l’ID utilisateur depuis le token
Au lieu de passer le userId en paramètre de route, récupérez-le depuis le token. Voir la section Récupération de l’utilisateur.
Ajoutez cette méthode helper dans vos contrôleurs :
private int? GetUserId()
{
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier);
if (userIdClaim == null || !int.TryParse(userIdClaim.Value, out int userId))
{
return null;
}
return userId;
}
Modification des routes
GameController
Toutes les routes doivent être protégées et ne plus prendre le userId en paramètre :
| Ancienne route | Nouvelle route |
|---|---|
GET /api/Game/Click/{userId} | GET /api/Game/Click |
GET /api/Game/Progression/{userId} | GET /api/Game/Progression |
GET /api/Game/Initialize/{userId} | GET /api/Game/Initialize |
POST /api/Game/Reset/{userId} | POST /api/Game/Reset |
GET /api/Game/ResetCost/{userId} | GET /api/Game/ResetCost |
Game Server API Documentation - Semaine 5
Authorization: Bearer <token>
Base URL: http://localhost:5000/api
Tables des autorisations par contrôleur
UserController
| Route | Méthode | Autorisation |
|---|---|---|
/api/User/Login | POST | Public |
/api/User/Register | POST | Public |
/api/User/{id} | GET | [Authorize] |
/api/User/{id} | PUT | [Authorize(Roles = "Admin")] |
/api/User/{id} | DELETE | [Authorize(Roles = "Admin")] |
/api/User/All | GET | [Authorize] |
/api/User/AllAdmin | GET | [Authorize(Roles = "Admin")] |
/api/User/Search/{name} | GET | [Authorize] |
GameController
| Route | Méthode | Autorisation |
|---|---|---|
/api/Game/Click | GET | [Authorize] |
/api/Game/Progression | GET | [Authorize] |
/api/Game/Initialize | GET | [Authorize] |
/api/Game/Reset | POST | [Authorize] |
/api/Game/ResetCost | GET | [Authorize] |
/api/Game/BestScore | GET | [Authorize] |
InventoryController
| Route | Méthode | Autorisation |
|---|---|---|
/api/Inventory/Seed | GET | Public |
/api/Inventory/Items | GET | Public |
/api/Inventory/UserInventory | GET | [Authorize] |
/api/Inventory/Buy/{itemId} | POST | [Authorize] |
Routes avec modification du retour
Login
POST /api/User/Login
Body:
{
"username": "string",
"password": "string"
}
Ancien retour: UserPublic
Nouveau retour:
{
"token": "string",
"user": UserPublic
}
Register
POST /api/User/Register
Body:
{
"username": "string",
"password": "string"
}
Ancien retour: UserPublic
Nouveau retour:
{
"token": "string",
"user": UserPublic
}