La gestion des autorisations est un aspect crucial du développement d'applications modernes en .NET. Une implémentation robuste de l'authorization permet non seulement de sécuriser les ressources mais aussi d'offrir une expérience utilisateur fluide et personnalisée. Dans cet article, nous allons explorer les meilleures pratiques et patterns pour déployer efficacement l'authorization dans vos applications .NET.
Les fondamentaux de l'Authorization en .NET
L'authorization dans .NET repose sur plusieurs concepts clés :
- Claims : représentent des informations sur l'utilisateur
- Policies : définissent des règles d'accès
- Roles : groupent les permissions
- Requirements : spécifient des conditions d'autorisation
Configuration de base
// Program.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy("AdminPolicy", policy =>
policy.RequireClaim("Role", "Admin"));
options.AddPolicy("MinimumAge", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(18)));
});
services.AddScoped();
}
Implémentation des Requirements personnalisés
Les requirements permettent de créer des règles d'autorisation complexes :
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public int MinimumAge { get; }
public MinimumAgeRequirement(int minimumAge)
{
MinimumAge = minimumAge;
}
}
public class MinimumAgeHandler : AuthorizationHandler
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
MinimumAgeRequirement requirement)
{
var dateOfBirth = context.User.FindFirst(c => c.Type == "DateOfBirth");
if (dateOfBirth == null)
{
return Task.CompletedTask;
}
var age = CalculateAge(DateTime.Parse(dateOfBirth.Value));
if (age >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
Bonnes pratiques d'implémentation
- Utilisez des policies plutôt que des rôles directs
- Centralisez la logique d'autorisation
- Implémentez une stratégie de cache appropriée
- Validez les permissions au niveau API et UI
Pattern Resource-Based Authorization
public class DocumentAuthorizationHandler
: AuthorizationHandler
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
OperationAuthorizationRequirement requirement,
Document resource)
{
if (requirement.Name == Operations.Read.Name)
{
if (resource.IsPublic ||
context.User.Id == resource.OwnerId)
{
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
}
Gestion des erreurs et performances
Implémentez une gestion d'erreurs robuste :
public class AuthorizationMiddleware
{
private readonly RequestDelegate _next;
public AuthorizationMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (AuthorizationException ex)
{
context.Response.StatusCode = 403;
await context.Response.WriteAsJsonAsync(new
{
error = "Authorization failed",
details = ex.Message
});
}
}
}
Tests d'authorization
public class AuthorizationTests
{
[Fact]
public async Task AdminPolicy_ShouldSucceed_ForAdminUser()
{
// Arrange
var user = new ClaimsPrincipal(new ClaimsIdentity(new[]
{
new Claim("Role", "Admin")
}));
var authService = new AuthorizationService(
new AuthorizationOptions(),
new IAuthorizationHandler[] { new RoleHandler() });
// Act
var result = await authService.AuthorizeAsync(
user,
null,
"AdminPolicy");
// Assert
Assert.True(result.Succeeded);
}
}
Considérations de sécurité avancées
- Implémentez une rotation des tokens
- Utilisez des permissions granulaires
- Logging sécurisé des tentatives d'accès
- Validation des tokens côté serveur
Exemple de validation de token
public class TokenValidationMiddleware
{
private readonly RequestDelegate _next;
private readonly ITokenValidator _tokenValidator;
public TokenValidationMiddleware(
RequestDelegate next,
ITokenValidator tokenValidator)
{
_next = next;
_tokenValidator = tokenValidator;
}
public async Task InvokeAsync(HttpContext context)
{
var token = context.Request.Headers["Authorization"]
.FirstOrDefault()?.Split(" ").Last();
if (token != null && await _tokenValidator.ValidateAsync(token))
{
await _next(context);
}
else
{
context.Response.StatusCode = 401;
}
}
}
Conclusion
Une implémentation efficace de l'authorization en .NET nécessite une approche structurée et réfléchie. Les points clés à retenir sont :
- Utilisation des policies et requirements personnalisés
- Mise en place de tests robustes
- Gestion appropriée des erreurs
- Considérations de performance et de sécurité
En suivant ces recommandations et en utilisant les patterns présentés, vous pourrez mettre en place un système d'authorization fiable et maintenable dans vos applications .NET.