in Architettura Software, Informatica

Custom Role Validation in DotNet Core 8

Partendo dalla configurazione del post precedente, può rendersi necessario utilizzare un validatore custom per la gestione dei ruoli utenti. Non sempre possiamo utilizzare i claims provenienti dal jwt token, perchè ad esempio non ci vengono forniti. Potremmo, inoltre, trovarci all’interno di una configurazione particolare dove i ruoli sono definiti all’interno di tabelle database.

Ci vengono incontro una serie di interfacce e classi che permettono di intercettare tutto il flusso dell’autenticazione, verificando il tipo i ruoli richiesti all’interno di una singola action, validarli e restituire un ok oppure un fail al flusso .

In particolar modo verrà creata una classe a partire da:

AuthorizationHandler<RolesAuthorizationRequirement>

IAuthorizationHandler

ed in particolar modo di RoleAuthorizationRequirement.

Partiamo con la definizione di una nuova classe:

 public class RolesInDBAuthorizationHandler : AuthorizationHandler<RolesAuthorizationRequirement>, IAuthorizationHandler
 {
     protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RolesAuthorizationRequirement requirement)
     {

         if (context.User == null || !context.User.Identity!.IsAuthenticated)
         {
             context.Fail();
             return Task.CompletedTask;
         }

         var found = false;
         if (requirement.AllowedRoles == null || requirement.AllowedRoles.Any() == false)
         {
             found = true;
         }
         else
         {
             var userId = context.User.Claims.FirstOrDefault(a => a.Type == "user_id");

             //TODO: ADD DB CONTEXT OR SERVICE

             var roles = requirement.AllowedRoles;
             if (roles.FirstOrDefault() == "Administrator")
             {
                 found = true;
             }
         }

         if (found)
         {
             context.Succeed(requirement);
             return Task.CompletedTask;
         }
         
         context.Fail();
         return Task.CompletedTask;
     }
 }

Il metodo HandleRequirementAsync consente di intercettare il context della chiamata ed i requirement della chiamata stessa.

Alla riga 6 viene verificato il contesto e la presenza dell’utente. Nel caso in cui sia null oppure non sia autentication, viene gestito il fail della chiamata.

Nel caso in cui non ci siano requirements, oppure non siano stati definiti ruoli, viene restituito il success.

Altrimenti vengono verificati i ruoli associati all’utente (in questo non sono stati verificati, ma si può farlo banalmente iniettando il service per la gestione degli utenti) e nel caso in cui siano presenti si ritornerà un success, in caso contrario un file.

A questo punto basta semplicemente aggiungere [Authorize(Roles=”Administrator”)] per poter far accedere all’api solo agli utenti nel ruole Administrator.