La gestion de l'authentification et de l'autorisation est un aspect crucial du développement d'applications modernes en .NET. Auth0, en tant que solution Identity-as-a-Service (IDaaS), offre une approche robuste et flexible pour implémenter ces mécanismes de sécurité. Dans cet article, nous allons explorer en détail comment intégrer Auth0 dans une application ASP.NET Core, en nous concentrant particulièrement sur l'aspect autorisation.
Concepts fondamentaux d'Auth0 dans .NET
Avant de plonger dans l'implémentation, il est essentiel de comprendre les concepts clés :
- Tenant : Environnement Auth0 isolé pour votre application
- Application : Représentation de votre application .NET dans Auth0
- API : Configuration des endpoints protégés
- Roles & Permissions : Mécanismes de contrôle d'accès
Configuration initiale dans ASP.NET Core
Commençons par installer les packages NuGet nécessaires :
dotnet add package Auth0.AspNetCore.Authentication
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Configuration dans Program.cs :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = $"https://{Configuration["Auth0:Domain"]}/";
options.Audience = Configuration["Auth0:Audience"];
});
Implémentation des autorisations
Créons un gestionnaire d'autorisation personnalisé :
public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
HasScopeRequirement requirement)
{
// Vérifier si l'utilisateur possède le scope requis
var scopeClaim = context.User.Claims
.FirstOrDefault(c => c.Type == "scope" &&
c.Value == requirement.Scope);
if (scopeClaim != null)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
Configuration des politiques d'autorisation
Définition des politiques dans Program.cs :
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("read:messages", policy =>
policy.Requirements.Add(new HasScopeRequirement("read:messages")));
options.AddPolicy("write:messages", policy =>
policy.Requirements.Add(new HasScopeRequirement("write:messages")));
});
Application des autorisations aux contrôleurs
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class MessagesController : ControllerBase
{
[HttpGet]
[Authorize("read:messages")]
public IActionResult Get()
{
// Logique pour récupérer les messages
return Ok(new { message = "Messages récupérés avec succès" });
}
[HttpPost]
[Authorize("write:messages")]
public IActionResult Post([FromBody] MessageDto message)
{
// Logique pour créer un message
return Created("", new { message = "Message créé avec succès" });
}
}
Gestion des erreurs et middleware personnalisé
public class AuthenticationErrorHandler : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (SecurityTokenExpiredException)
{
context.Response.StatusCode = 401;
await context.Response.WriteAsJsonAsync(new
{
error = "Token expiré"
});
}
catch (SecurityTokenValidationException)
{
context.Response.StatusCode = 401;
await context.Response.WriteAsJsonAsync(new
{
error = "Token invalide"
});
}
}
}
Tests unitaires et d'intégration
public class AuthorizationTests
{
[Fact]
public async Task Get_WithValidToken_ReturnsOk()
{
// Arrangement
var client = _factory.CreateClient();
var token = await GetTestToken("read:messages");
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token);
// Action
var response = await client.GetAsync("/api/messages");
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
}
Bonnes pratiques et recommandations
- Utilisez des variables d'environnement pour les configurations sensibles
- Implémentez le caching des tokens pour optimiser les performances
- Validez toujours les tokens côté serveur
- Utilisez des scopes granulaires pour un contrôle précis
- Implémentez une stratégie de refresh token
Considérations de performance
Pour optimiser les performances :
services.AddMemoryCache();
services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();
services.AddAuthentication()
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
});
Conclusion
L'implémentation de l'autorisation avec Auth0 dans une application ASP.NET Core nécessite une compréhension approfondie des concepts de sécurité et des bonnes pratiques. En suivant les recommandations et patterns présentés dans cet article, vous pouvez créer une solution d'autorisation robuste et maintenable.
Points clés à retenir :
- Configurez correctement votre application dans Auth0
- Utilisez les politiques d'autorisation de manière granulaire
- Implémentez une gestion d'erreurs appropriée
- Testez rigoureusement votre implémentation
- Surveillez les performances et optimisez si nécessaire