using System.Security.Claims; using Microsoft.AspNetCore.Authorization; public class PermissionAuthorizationHandler : AuthorizationHandler { private readonly ILogger _logger; private readonly IHttpContextAccessor _http; private readonly ClinicalMetrics _metrics; public PermissionAuthorizationHandler( ILogger logger, IHttpContextAccessor http, ClinicalMetrics metrics) { _logger = logger; _http = http; _metrics = metrics; } protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, PermissionRequirement requirement) { var roleClaim = context.User.FindFirst("clinical_role")?.Value; if (roleClaim is null) { LogAuthorizationFailure(context.User, "none", requirement.Permission); return Task.CompletedTask; } var role = ClinicalRoleExtensions.FromDbString(roleClaim); if (ClinicalRolePermissionMap.HasPermission(role, requirement.Permission)) { context.Succeed(requirement); } else { LogAuthorizationFailure(context.User, roleClaim, requirement.Permission); } return Task.CompletedTask; } private void LogAuthorizationFailure(ClaimsPrincipal user, string role, string permission) { var username = user.FindFirst(ClaimTypes.Name)?.Value ?? "unknown"; var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? "unknown"; var endpoint = _http.HttpContext?.GetEndpoint()?.DisplayName ?? "unknown"; _logger.LogWarning( "Authorization denied: user={User} (id={UserId}), role={Role}, " + "requiredPermission={Permission}, endpoint={Endpoint}", username, userId, role, permission, endpoint); _metrics.AuthorizationFailuresTotal.WithLabels(permission, role).Inc(); } }