Come implementare le autorizzazioni di ruolo nel livello di servizio?

4

Nel mio progetto corrente ho una classe Report , e ho intenzione di implementare un livello di servizio per questo. Ogni metodo sarà consentito solo per alcuni ruoli. In questo modo:

public class ReportService : IReportService
{
    public void CreateReport(Report report, User user)
    {
        if(user.HasRole("Admin"))
        {
            throw new SecurityException("You do not have permissions to do it");
        }

        ...
    }

    public void ModifyReport(Report report, User user)
    {
        if(user.HasRole("Admin"))
        {
            throw new SecurityException("You do not have permissions to do it");
        }

        ...
    }

    public bool ValidateReport(Report report, User user)
    {
        if (!user.HasRole("Manager"))
        {
            throw new SecurityException("You do not have permissions to do it");
        }
    }

    public void DeleteReport(Report report, User user)
    {
        if (user.HasRole("Employee") || user.HasRole("Manager"))
        {
            throw new SecurityException("You do not have permissions to do it");
        }
        ...
    }
}

Questo approccio diretto è OK? Hai delle idee migliori?
Ho solo un'idea per implementarlo come schema di decorazione , quindi il codice sarà simile a questo:

public class ReportService : IReportService
{
    public void CreateReport(Report report, User user)
    {
      // Actual implementation
    }

    public void ModifyReport(Report report, User user)
    {
        // Actual implementation
    }

    public bool ValidateReport(Report report, User user)
    {
        // Actual implementation
    }

    public void DeleteReport(Report report, User user)
    {
        // Actual implementation
    }
}

public class PermissionsReportService : IReportService
{
    private IReportSerivce _service;
    public PermissionsReportService(IReportService service)
    {
        _service = service;
    }

    public void CreateReport(Report report, User user)
    {
        if (user.HasRole("Admin"))
        {
            throw new SecurityException("You do not have permissions to do it");
        }

        _service.CreateReport(report, user);
    }

    public void ModifyReport(Report report, User user)
    {
        if (user.HasRole("Admin"))
        {
            throw new SecurityException("You do not have permissions to do it");
        }
        _service.ModifyReport(report, user);
    }

    public bool ValidateReport(Report report, User user)
    {
        if (!user.HasRole("Manager"))
        {
            throw new SecurityException("You do not have permissions to do it");
        }

        _service.ValidateReport(report, user);
    }

    public void DeleteReport(Report report, User user)
    {
        if (user.HasRole("Employee") || user.HasRole("Manager"))
        {
            throw new SecurityException("You do not have permissions to do it");
        }

        _service.DeleteReport(report, user);
    }
}

Sembra meglio perché il controllo delle autorizzazioni di ruolo e la logica sono ora divisi, vero?

Anch'io ho un'altra preoccupazione. Molto probabilmente questo servizio verrà utilizzato nel progetto ASP.NET MVC e Microsoft propone di utilizzare gli attributi di Authorize per diversi permessi di ruolo, come

 public class ReportController : Controller
{
    [HttpGet]
    [Authorize(Roles="Admin")]
    public void DeleteReport(int reportId)
    {

    }
}

Se utilizzo questo approccio duplicherò la logica dei permessi di ruolo (all'interno del livello di servizio e all'interno del controller). Cosa dovrei fare? Devo rifiutare l'approccio di Microsoft? O devo rimuovere il controllo dei permessi di ruolo nel livello di servizio (ma in questo caso cosa devo fare se il mio servizio verrà utilizzato in un'applicazione console (ad esempio))? O è OK avere questa duplicazione del codice e avere controlli delle autorizzazioni nel servizio e nei livelli web?

    
posta Disappointed 10.07.2015 - 10:33
fonte

1 risposta

4

Direi di abbandonare entrambi a favore di una classe che gestisce tutte le autorizzazioni. Le classi passerebbero quindi un identificatore di stringa del permesso che si desidera controllare e la classe eseguirà una ricerca per vedere quali ruoli sono necessari per eseguire quell'azione.

Ad esempio, piuttosto che avere un metodo come:

public void CreateReport(Report report, User user)
{
    if(user.HasRole("Admin"))
    {
        throw new SecurityException("You have not permissions to do it");
    }

    ...
}

Mi aspetterei qualcosa di più simile a

public void CreateReport(Report report, UserAuth auth)
{
    auth.Validate("report.create");  // throws SecurityException if invalid

    ...
}

La classe UserAuth prenderebbe un'istanza utente e genererebbe un SecurityException se l'utente non ha i ruoli richiesti per eseguire quell'azione. Idealmente il collegamento tra azione e quali ruoli sono richiesti verrebbe caricato dinamicamente da un database, sebbene sia possibile iniziare con un semplice dizionario.

Userei ancora la facciata per separare l'effettivo controllo dei permessi e l'azione reale, perché a mio modesto parere, questa è una separazione delle preoccupazioni e dovrebbe essere tenuta in una classe separata allo stesso modo.

Il tuo controller farebbe lo stesso. Ciò che è importante è che la logica dietro le autorizzazioni sia nella sua stessa classe. Devi ancora chiamarlo, ma non devi preoccuparti di altro se non quello che viene chiamato il permesso che stai cercando di cercare. Per esempio, se un utente ha un ruolo di dipendente o amministratore per ogni chiamata al metodo che merita tale controllo, ad esempio, è una specie di antipattern.

Spero che ti aiuti!

    
risposta data 10.07.2015 - 11:59
fonte

Leggi altre domande sui tag