Tutorial ed esempi/Authorization Helper

Authorization Helper

Autorizzazioni personalizzate in ASP.NET

Con riferimento a "Provider di criteri di autorizzazione personalizzati

Vogliamo ottenere un risulatato di questo tipo: una policy custom che autorizzerà l'utente all'accesso solo se l'utente appartiene a una unit specificata in un file di configurazione.


// Controller
[Authorize(Policy = "UserCanNavigate")]
public IActionResult Index()
{
    return  View();
}

Questo decoratore dichiara che l'azione Index è accessibile solo da utenti che rispettino le condizioni della nostra policy UserCanNavigate. 
Questa tipologia di decoratore in .net può essere applicata a più livelli: intere aree, singoli controller, singole azioni o pagine razor.
Ulteriori informazioni possono essere recuperate a https://learn.microsoft.com/en-us/aspnet/core/security/authorization/simple

Per costruire ciò, iniziamo a costruire una classe che contenga il Requirement. Questo sarà, in questo caso, estremamente semplice, ma in casi più articolati conterrà i parametri forniti al decoratore.


// Requirement class. Does not need to be strictly internal
internal class UserCanNavigateRequirement : IAuthorizationRequirement
{ }

A questo punto costruiamo anche l'handler della policy, il quale conterrà la business logic del nostro decoratore.


// Auth handler. This will check if a user is in a unit whose id is in a configuration file
internal class UserCanNavigateHandler : AuthorizationHandler
{
    private readonly IUserRepo _userRepo;
    private readonly AuthorizationSettings _authorizationSettings;
    protected UserSessionData UserSessionData { get; set; }     // Il costruttore inietta il servizio user, i dati di sessione dello user che fa la richiesta e i dati di configurazione inerenti all'autorizzazione. Da quest'ultimo recupereremo l'id della unit.
    public UserCanNavigateHandler(IUserRepo userRepo,
        ISessionHelper sessionHelper,
        IHttpContextAccessor accessor,
        IOptions authorizationSettings)
    {
        _userRepo = userRepo;
        _authorizationSettings = authorizationSettings.Value;
        UserSessionData = sessionHelper.GetDatiUtente(accessor.HttpContext);
    }     protected async override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserCanNavigateRequirement requirement)
    {
        // Se non troviamo uno user nella session, probabilmente non siamo loggati. In ogni caso, la nostra policy respinge la richiesta.
        if(UserSessionData == null)
        {
            context.Fail();
        }
        else
        {
            // Recuperiamo tutte le unit di cui l'utente fa parte
            var units = await _userRepo.GetUnitsByUser(UserSessionData.UserToken);
            if (units.Select(u => u.Id).Contains(_authorizationSettings.BasicNavigatorUserUnitId))
            {
                context.Succeed(requirement);
            }
            else
            {
                context.Fail();
            }
        }
                 //return Task.CompletedTask;
    }
}

Concludiamo registrando la policy. Per fare questo, all'aggiunta del servizio di autorizzazione indichiamo la nostra nuova policy


// Startup or service building
services.AddAuthorization(options =>
{
    options.AddPolicy("UserCanNavigate", policy =>
        policy.Requirements.Add(new UserCanNavigateRequirement()));
});

An error has occurred. This application may no longer respond until reloaded. Reload 🗙