Gestion des utilisateurs
Notions théoriques
Qu'est-ce qu'ASP.NET Core Identity ?
ASP.NET Core Identity est le système d'authentification et de gestion des utilisateurs intégré à ASP.NET Core. Il fournit :
- Inscription (création de compte avec mot de passe haché automatiquement)
- Connexion (vérification du mot de passe + création de cookie de session)
- Déconnexion
- Gestion des rôles (
Admin,Auteur,Lecteur...) - Protection de routes avec
[Authorize]
| Framework | Système d'authentification |
|---|---|
| ASP.NET Core | ASP.NET Core Identity |
| Symfony | Security Bundle (Guard, Voters) |
| Spring Boot | Spring Security |
Dans les trois frameworks, le hachage des mots de passe (BCrypt) est géré automatiquement. Vous ne stockez et ne comparez jamais les mots de passe en clair.
Installer le package Identity
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore
Configurer Identity
1. Créer ApplicationUser (votre classe utilisateur, qui hérite de IdentityUser) :
// Models/ApplicationUser.cs
using Microsoft.AspNetCore.Identity;
public class ApplicationUser : IdentityUser
{
// Propriétés supplémentaires spécifiques à MonBlog
public string NomComplet { get; set; } = string.Empty;
public DateTime DateInscription { get; set; } = DateTime.UtcNow;
}
2. Faire hériter le DbContext de IdentityDbContext :
// Data/MonBlogContext.cs
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
public class MonBlogContext : IdentityDbContext<ApplicationUser>
{
public MonBlogContext(DbContextOptions<MonBlogContext> options) : base(options) { }
public DbSet<Article> Articles { get; set; }
// Identity ajoute automatiquement : AspNetUsers, AspNetRoles, AspNetUserRoles...
}
3. Configurer Identity dans Program.cs :
// Program.cs
builder.Services.AddDbContext<MonBlogContext>(options =>
options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)));
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Password.RequiredLength = 8;
options.Password.RequireDigit = true;
options.Password.RequireUppercase = false; // Assouplissement pour les débutants
options.SignIn.RequireConfirmedAccount = false;
})
.AddEntityFrameworkStores<MonBlogContext>()
.AddDefaultTokenProviders();
// Après builder.Build() :
app.UseAuthentication(); // Avant UseAuthorization !
app.UseAuthorization();
Inscription d'un utilisateur
// Controllers/AccountController.cs
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
// GET /Account/Register
public IActionResult Register() => View();
// POST /Account/Register
[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
if (!ModelState.IsValid) return View(model);
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
NomComplet = model.NomComplet,
};
// Identity hache automatiquement le mot de passe (BCrypt)
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
// Ajouter les erreurs Identity à ModelState
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
return View(model);
}
}
Connexion et déconnexion
// POST /Account/Login
[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model)
{
if (!ModelState.IsValid) return View(model);
var result = await _signInManager.PasswordSignInAsync(
model.Email,
model.Password,
isPersistent: model.RememberMe, // "Se souvenir de moi"
lockoutOnFailure: true); // Bloquer après trop d'échecs
if (result.Succeeded)
return RedirectToAction("Index", "Home");
ModelState.AddModelError(string.Empty, "Email ou mot de passe incorrect.");
return View(model);
}
// POST /Account/Logout
[HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
{
await _signInManager.SignOutAsync();
return RedirectToAction("Index", "Home");
}
Protéger les routes avec [Authorize]
// Require une connexion pour toutes les actions du contrôleur
[Authorize]
public class ArticlesController : Controller
{
// GET /Articles/Create — accessible seulement si connecté
public IActionResult Create() => View();
}
// Ou protéger une action spécifique
public class HomeController : Controller
{
public IActionResult Index() => View(); // Public
[Authorize] // Requiert connexion
public IActionResult Profil() => View();
[Authorize(Roles = "Admin")] // Requiert rôle Admin
public IActionResult Admin() => View();
}
Dans les vues Razor, vérifier si l'utilisateur est connecté :
@using Microsoft.AspNetCore.Identity
@inject SignInManager<ApplicationUser> SignInManager
@if (SignInManager.IsSignedIn(User))
{
<a asp-controller="Account" asp-action="Logout">Déconnexion</a>
}
else
{
<a asp-controller="Account" asp-action="Login">Connexion</a>
}
Exemple pratique
ViewModel pour l'inscription et la connexion :
// ViewModels/RegisterViewModel.cs
using System.ComponentModel.DataAnnotations;
public class RegisterViewModel
{
[Required, MaxLength(100)]
[Display(Name = "Nom complet")]
public string NomComplet { get; set; } = string.Empty;
[Required, EmailAddress]
[Display(Name = "Adresse e-mail")]
public string Email { get; set; } = string.Empty;
[Required]
[StringLength(100, MinimumLength = 8, ErrorMessage = "Le mot de passe doit contenir au moins 8 caractères.")]
[DataType(DataType.Password)]
[Display(Name = "Mot de passe")]
public string Password { get; set; } = string.Empty;
[Required]
[DataType(DataType.Password)]
[Display(Name = "Confirmer le mot de passe")]
[Compare("Password", ErrorMessage = "Les mots de passe ne correspondent pas.")]
public string ConfirmPassword { get; set; } = string.Empty;
}
// ViewModels/LoginViewModel.cs
using System.ComponentModel.DataAnnotations;
public class LoginViewModel
{
[Required, EmailAddress]
[Display(Name = "Adresse e-mail")]
public string Email { get; set; } = string.Empty;
[Required, DataType(DataType.Password)]
[Display(Name = "Mot de passe")]
public string Password { get; set; } = string.Empty;
[Display(Name = "Se souvenir de moi")]
public bool RememberMe { get; set; }
}
ASP.NET Core Identity génère automatiquement les tables AspNetUsers, AspNetRoles, AspNetUserRoles via les migrations EF Core. Après avoir configuré Identity, générez une migration : dotnet ef migrations add AjoutIdentity.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des probl èmes
Vous allez configurer ASP.NET Core Identity dans MonBlog et créer la page d'inscription.
Étape 1 — Configurer Identity dans Program.cs
En développement avec des étudiants, assoupliez les règles de mot de passe (RequireUppercase = false, RequireNonAlphanumeric = false) pour faciliter les tests. En production, appliquez des règles strictes pour la sécurité des vrais utilisateurs.
Étape 2 — Créer le formulaire d'inscription
Connecter l'utilisateur automatiquement après l'inscription améliore l'expérience utilisateur (pas besoin de se connecter manuellement). L'option isPersistent: false crée un cookie de session (expiré à la fermeture du navigateur). Utilisez isPersistent: true pour "Se souvenir de moi".
Étape 3 — Générer la migration Identity
Créez une migration distincte pour l'ajout d'Identity (plutôt que de la mélanger à d'autres changements). Cela facilite la lecture de l'historique Git et permet de faire un rollback ciblé si nécessaire.