Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
di Rick Anderson
È stata creata un'API Web, ma ora si vuole controllare l'accesso. In questa serie di articoli verranno esaminate alcune opzioni per proteggere un'API Web da utenti non autorizzati. Questa serie illustra sia l'autenticazione che l'autorizzazione.
- L'autenticazione conosce l'identità dell'utente. Ad esempio, Alice accede con il nome utente e la password e il server usa la password per autenticare Alice.
- L'autorizzazione decide se un utente è autorizzato a eseguire un'azione. Ad esempio, Alice ha l'autorizzazione per ottenere una risorsa, ma non creare una risorsa.
Il primo articolo della serie offre una panoramica generale dell'autenticazione e dell'autorizzazione in ASP.NET API Web. Altri argomenti descrivono scenari di autenticazione comuni per l'API Web.
Annotazioni
Grazie alle persone che hanno esaminato questa serie e fornito feedback prezioso: Rick Anderson, Levi Broderick, Barry Dorrans, Tom Dykstra, Hongmei Ge, David Matson, Daniel Roth, Tim Teebken.
Autenticazione
L'API Web presuppone che l'autenticazione venga eseguita nell'host. Per l'hosting Web, l'host è IIS, che usa moduli HTTP per l'autenticazione. È possibile configurare il progetto in modo da usare uno dei moduli di autenticazione incorporati in IIS o ASP.NET oppure scrivere il proprio modulo HTTP per eseguire l'autenticazione personalizzata.
Quando l'host autentica l'utente, crea un principal, ovvero un oggetto IPrincipal che rappresenta il contesto di sicurezza in cui è in esecuzione il codice. L'host collega l'entità al thread corrente impostando Thread.CurrentPrincipal. Il principale contiene un oggetto Identity associato che contiene informazioni sull'utente. Se l'utente è autenticato, la proprietà Identity.IsAuthenticated restituisce true. Per le richieste anonime, IsAuthenticated restituisce false. Per ulteriori informazioni sui principali, vedere Role-Based Security.
Gestori di messaggi HTTP per l'autenticazione
Anziché usare l'host per l'autenticazione, è possibile inserire la logica di autenticazione in un gestore di messaggi HTTP. In tal caso, il gestore messaggi esamina la richiesta HTTP e imposta il principale.
Quando è consigliabile usare i gestori di messaggi per l'autenticazione? Ecco alcuni compromessi:
- Un modulo HTTP visualizza tutte le richieste che passano attraverso la pipeline di ASP.NET. Un gestore di messaggi visualizza solo le richieste indirizzate all'API Web.
- È possibile impostare gestori di messaggi per route, che consente di applicare uno schema di autenticazione a una route specifica.
- I moduli HTTP sono specifici di IIS. I gestori di messaggi sono indipendenti dall'host, quindi possono essere usati con hosting Web e self-hosting.
- I moduli HTTP partecipano alla registrazione, al controllo e così via di IIS.
- I moduli HTTP vengono eseguiti in precedenza nella pipeline. Se si gestisce l'autenticazione in un gestore di messaggi, il principale non viene impostato fino a quando il gestore non viene eseguito. Inoltre, il principale torna al precedente principale quando la risposta lascia il gestore di messaggi.
In genere, se non è necessario supportare l'hosting automatico, un modulo HTTP è un'opzione migliore. Se è necessario supportare l'hosting automatico, prendere in considerazione un gestore di messaggi.
Impostazione del Principale
Se l'applicazione esegue una logica di autenticazione personalizzata, è necessario impostare il principale in due posizioni:
- Thread.CurrentPrincipal. Questa proprietà è il modo standard per impostare il principale del thread in .NET.
- HttpContext.Current.User. Questa proprietà è specifica per ASP.NET.
Il codice seguente illustra come impostare l'entità:
private void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
Per l'hosting Web, è necessario impostare il principale in entrambe le posizioni; in caso contrario, il contesto di sicurezza può diventare incompatibile. Per l'hosting automatico, tuttavia, HttpContext.Current è null. Per assicurarsi che il codice sia indipendente dall'host, verificare quindi la presenza di null prima di assegnare a HttpContext.Current, come illustrato.
Autorizzazione
L'autorizzazione viene eseguita più avanti nella pipeline, più vicina al controller. Ciò consente di effettuare scelte più granulari quando si concede l'accesso alle risorse.
- I filtri di autorizzazione vengono eseguiti prima dell'azione del controller. Se la richiesta non è autorizzata, il filtro restituisce una risposta di errore e l'azione non viene richiamata.
- All'interno di un'azione di un controller, puoi ottenere l'entità corrente dalla proprietà ApiController.User. Ad esempio, è possibile filtrare un elenco di risorse in base al nome utente, restituendo solo le risorse che appartengono a tale utente.
Uso dell'attributo [Authorize]
L'API Web fornisce un filtro di autorizzazione predefinito , AuthorizeAttribute. Questo filtro controlla se l'utente è autenticato. In caso contrario, restituisce il codice di stato HTTP 401 (non autorizzato), senza richiamare l'azione.
È possibile applicare il filtro a livello globale, a livello di controller o a livello di singole azioni.
Globale: per limitare l'accesso per ogni controller API Web, aggiungere il filtro AuthorizeAttribute all'elenco di filtri globale:
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new AuthorizeAttribute());
}
Controller: per limitare l'accesso per un controller specifico, aggiungere il filtro come attributo al controller:
// Require authorization for all actions on the controller.
[Authorize]
public class ValuesController : ApiController
{
public HttpResponseMessage Get(int id) { ... }
public HttpResponseMessage Post() { ... }
}
Azione: per limitare l'accesso per azioni specifiche, aggiungere l'attributo al metodo di azione:
public class ValuesController : ApiController
{
public HttpResponseMessage Get() { ... }
// Require authorization for a specific action.
[Authorize]
public HttpResponseMessage Post() { ... }
}
In alternativa, è possibile limitare il controller e quindi consentire l'accesso anonimo a azioni specifiche usando l'attributo [AllowAnonymous] . Nell'esempio seguente il Post metodo è limitato, ma il Get metodo consente l'accesso anonimo.
[Authorize]
public class ValuesController : ApiController
{
[AllowAnonymous]
public HttpResponseMessage Get() { ... }
public HttpResponseMessage Post() { ... }
}
Negli esempi precedenti, il filtro consente a qualsiasi utente autenticato di accedere ai metodi con restrizioni; vengono mantenuti solo gli utenti anonimi. È anche possibile limitare l'accesso a utenti specifici o a utenti in ruoli specifici:
// Restrict by user:
[Authorize(Users="Alice,Bob")]
public class ValuesController : ApiController
{
}
// Restrict by role:
[Authorize(Roles="Administrators")]
public class ValuesController : ApiController
{
}
Annotazioni
Il filtro AuthorizeAttribute per i controller API Web si trova nello spazio dei nomi System.Web.Http . Esiste un filtro simile per i controller MVC nello spazio dei nomi System.Web.Mvc , che non è compatibile con i controller API Web.
Filtri di autorizzazione personalizzati
Per scrivere un filtro di autorizzazione personalizzato, derivare da uno di questi tipi:
- AuthorizeAttribute. Estendere questa classe per eseguire la logica di autorizzazione in base all'utente corrente e ai ruoli dell'utente.
- AuthorizationFilterAttribute. Estendere questa classe per eseguire la logica di autorizzazione sincrona che non è necessariamente basata sull'utente o sul ruolo corrente.
- IAuthorizationFilter. Implementare questa interfaccia per eseguire la logica di autorizzazione asincrona; ad esempio, se la logica di autorizzazione effettua chiamate di I/O asincrone o di rete. Se la logica di autorizzazione è associata alla CPU, è più semplice derivare da AuthorizationFilterAttribute, perché non è necessario scrivere un metodo asincrono.
Il diagramma seguente mostra la gerarchia di classi per la classe AuthorizeAttribute .
Diagramma della gerarchia di classi per la classe Authorize Attribute. Authorize Attribute si trova nella parte inferiore, con una freccia rivolta verso l'alto su Authorization Filter Attribute (Attributo filtro autorizzazione) e una freccia che punta fino al filtro di autorizzazione I nella parte superiore.
Autorizzazione all'interno di un'azione del controller
In alcuni casi, è possibile consentire a una richiesta di procedere, ma modificare il comportamento in base all'entità. Ad esempio, le informazioni restituite potrebbero cambiare a seconda del ruolo dell'utente. All'interno di un metodo controller, è possibile ottenere l'entità corrente dalla proprietà ApiController.User .
public HttpResponseMessage Get()
{
if (User.IsInRole("Administrators"))
{
// ...
}
}