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.
Questa guida illustra come implementare l'autorizzazione nelle API Web ASP.NET Core usando Microsoft. Identity.Web. L'autorizzazione garantisce che i chiamanti autenticati dispongano degli ambiti necessari (autorizzazioni delegate) o delle autorizzazioni dell'app (autorizzazioni dell'applicazione ) per accedere alle risorse protette.
Informazioni generali
Autenticazione e autorizzazione
| Concetto | Scopo | Result |
|---|---|---|
| Autenticazione | Verificare l'identità | 401 Non autorizzato se ha esito negativo |
| Autorizzazione | Verificare le autorizzazioni | 403 Proibito se non sufficiente |
Cosa viene convalidato?
Quando un'API Web riceve un token di accesso, Microsoft. Identity.Web convalida:
- Firma del token : proviene da un'autorità attendibile?
- Destinatari dei token : è destinato a questa API?
- Scadenza del token : è ancora valida?
- Ambiti/Ruoli - L'app client e il soggetto (utente) hanno le autorizzazioni corrette?
Questa guida è incentrata sul numero 4: convalida degli ambiti e delle autorizzazioni dell'app.
Concetti relativi all'autorizzazione
Ambiti (autorizzazioni delegate)
Usato quando: Un utente delega l'autorizzazione a un'app per agire per suo conto.
Attestazione token:scp o scope per l'app client Valori di esempio:"access_as_user", "User.Read", "Files.ReadWrite"
Attestazione token:rolesValori di esempio:"admin""SimpleUser" per l'utente.
Scenario: Web API per conto dell'utente autenticato.
Autorizzazioni per le app (autorizzazioni dell'applicazione)
Usato quando: API Web chiamata da un'app che funge da solo (nessun contesto utente), ad esempio un servizio daemon/in background.
Attestazione token:rolesValori di esempio:"Mail.Read.All", "User.Read.All"
Scenario: L'app daemon chiama l'API Web usando le credenziali client.
Convalida dell'ambito con RequiredScope
L'attributo RequiredScope convalida che il token di accesso contenga almeno uno degli ambiti specificati.
Avvio rapido
1. Abilitare l'autorizzazione nell'API:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(); // Required for authorization
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization(); // Must be after UseAuthentication
app.MapControllers();
app.Run();
2. Proteggere controller o azioni:
using Microsoft.AspNetCore.Authorization;
using Microsoft.Identity.Web.Resource;
[Authorize]
[RequiredScope("access_as_user")]
public class TodoListController : ControllerBase
{
[HttpGet]
public IActionResult GetTodos()
{
// Only accessible if token has "access_as_user" scope
return Ok(new[] { "Todo 1", "Todo 2" });
}
}
Modelli di utilizzo
Modello 1: Ambiti codificati in modo rigido
Usare quando: Gli ambiti sono fissi e noti in fase di sviluppo.
[Authorize]
[RequiredScope("access_as_user")]
public class TodoListController : ControllerBase
{
// All actions require "access_as_user" scope
}
Più ambiti (se uno è corrispondente):
[Authorize]
[RequiredScope("read", "write", "admin")]
public class TodoListController : ControllerBase
{
// Token must have "read" OR "write" OR "admin"
}
Modello 2: Ambiti dalla configurazione
Usare quando: Gli ambiti devono essere configurabili per ogni ambiente.
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-api-client-id",
"Scopes": "access_as_user read write"
}
}
Controller:
[Authorize]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class TodoListController : ControllerBase
{
// Scopes read from configuration
}
** Vantaggio:** Modificare gli ambiti senza ricompilare.
Modello 3: ambiti di Action-Level
Usare quando: Diverse azioni richiedono autorizzazioni diverse.
[Authorize]
public class TodoListController : ControllerBase
{
[HttpGet]
[RequiredScope("read")]
public IActionResult GetTodos()
{
return Ok(todos);
}
[HttpPost]
[RequiredScope("write")]
public IActionResult CreateTodo([FromBody] Todo todo)
{
// Only tokens with "write" scope can create
return CreatedAtAction(nameof(GetTodos), todo);
}
[HttpDelete("{id}")]
[RequiredScope("admin")]
public IActionResult DeleteTodo(int id)
{
// Only tokens with "admin" scope can delete
return NoContent();
}
}
Come funziona
Quando arriva una richiesta:
- ASP.NET Core middleware di autenticazione convalida il token
-
RequiredScopel'attributo verifica la presenza dell'attestazionescposcope - Se il token contiene almeno un ambito corrispondente → la richiesta procede
- Se non è stato trovato alcun ambito corrispondente → risposta 403 Accesso negato
Esempio di risposta di errore:
{
"error": "insufficient_scope",
"error_description": "The token does not have the required scope 'access_as_user'."
}
Autorizzazioni dell'app con RequiredScopeOrAppPermission
L'attributo RequiredScopeOrAppPermission convalida gli ambiti (delegati) o le autorizzazioni dell'app (applicazione).
Quando utilizzare
** Usa RequiredScopeOrAppPermission quando:**
- La tua API supporta sia le applicazioni delegate dagli utenti che le applicazioni daemon/servizio
- Lo stesso endpoint deve accettare token da applicazioni web (ambiti) o servizi in background (autorizzazioni delle app)
** Usa RequiredScope quando:**
- L'API gestisce solo le richieste delegate dall'utente
Avvio rapido
using Microsoft.Identity.Web.Resource;
[Authorize]
[RequiredScopeOrAppPermission(
AcceptedScope = new[] { "access_as_user" },
AcceptedAppPermission = new[] { "TodoList.ReadWrite.All" }
)]
public class TodoListController : ControllerBase
{
[HttpGet]
public IActionResult GetTodos()
{
// Accessible with EITHER:
// - User-delegated token with "access_as_user" scope, OR
// - App-only token with "TodoList.ReadWrite.All" app permission
return Ok(todos);
}
}
Autorizzazioni delle app basate su configurazione
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-api-client-id",
"Scopes": "access_as_user",
"AppPermissions": "TodoList.ReadWrite.All TodoList.Admin"
}
}
Controller:
[Authorize]
[RequiredScopeOrAppPermission(
RequiredScopesConfigurationKey = "AzureAd:Scopes",
RequiredAppPermissionsConfigurationKey = "AzureAd:AppPermissions"
)]
public class TodoListController : ControllerBase
{
// Scopes and app permissions from configuration
}
Differenze nelle richieste dei token
| Tipo di token | Richiesta di rimborso | Valore di esempio |
|---|---|---|
| Delegata dall'utente |
scp oppure scope |
"access_as_user User.Read" |
| Solo app | roles |
["TodoList.ReadWrite.All"] |
Esempio: Token delegato dall'utente:
{
"aud": "api://your-api-client-id",
"iss": "https://login.microsoftonline.com/.../v2.0",
"scp": "access_as_user",
"sub": "user-object-id",
...
}
Esempio: Token solo per app:
{
"aud": "api://your-api-client-id",
"iss": "https://login.microsoftonline.com/.../v2.0",
"roles": ["TodoList.ReadWrite.All"],
"sub": "app-object-id",
...
}
Criteri di autorizzazione
Per scenari di autorizzazione più complessi, usare ASP.NET Core criteri di autorizzazione.
Perché usare i criteri?
- Logica centralizzata : definire le regole di autorizzazione una sola volta, riutilizzare ovunque
- Componibile : combinare più requisiti (ambiti + attestazioni e logica personalizzata)
- Testable : logica di autorizzazione di unit test più semplice
- Flessibile - Requisiti personalizzati oltre la convalida dell'ambito
Modello 1: Politica con RequireScope
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("TodoReadPolicy", policyBuilder =>
{
policyBuilder.RequireScope("read", "access_as_user");
});
options.AddPolicy("TodoWritePolicy", policyBuilder =>
{
policyBuilder.RequireScope("write", "admin");
});
});
var app = builder.Build();
Controller:
[Authorize]
public class TodoListController : ControllerBase
{
[HttpGet]
[Authorize(Policy = "TodoReadPolicy")]
public IActionResult GetTodos()
{
return Ok(todos);
}
[HttpPost]
[Authorize(Policy = "TodoWritePolicy")]
public IActionResult CreateTodo([FromBody] Todo todo)
{
return CreatedAtAction(nameof(GetTodos), todo);
}
}
Modello 2: Policy con ScopeAuthorizationRequirement
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("CustomPolicy", policyBuilder =>
{
policyBuilder.AddRequirements(
new ScopeAuthorizationRequirement(new[] { "access_as_user" })
);
});
});
Modello 3: Criterio predefinito (si applica a tutti [autorizza])
builder.Services.AddAuthorization(options =>
{
var defaultPolicy = new AuthorizationPolicyBuilder()
.RequireScope("access_as_user")
.Build();
options.DefaultPolicy = defaultPolicy;
});
Ora ogni [Authorize] attributo richiede automaticamente l'ambito "access_as_user":
[Authorize] // Automatically requires "access_as_user" scope
public class TodoListController : ControllerBase
{
// All actions protected by default policy
}
Modello 4: Combinazione di più requisiti
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminPolicy", policyBuilder =>
{
policyBuilder.RequireScope("admin");
policyBuilder.RequireRole("Admin"); // Also check role claim
policyBuilder.RequireAuthenticatedUser();
});
});
Modello 5: criteri basati su configurazione
var requiredScopes = builder.Configuration["AzureAd:Scopes"]?.Split(' ');
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("ApiAccessPolicy", policyBuilder =>
{
if (requiredScopes != null)
{
policyBuilder.RequireScope(requiredScopes);
}
});
});
Filtro dei tenant
Limitare l'accesso API agli utenti solo da tenant specifici.
caso d'uso
Scenario: L'API multi-tenant deve accettare token solo dai clienti approvati.
Implementation
builder.Services.AddAuthorization(options =>
{
string[] allowedTenants =
{
"14c2f153-90a7-4689-9db7-9543bf084dad", // Contoso tenant
"af8cc1a0-d2aa-4ca7-b829-00d361edb652", // Fabrikam tenant
"979f4440-75dc-4664-b2e1-2cafa0ac67d1" // Northwind tenant
};
options.AddPolicy("AllowedTenantsOnly", policyBuilder =>
{
policyBuilder.RequireClaim(
"http://schemas.microsoft.com/identity/claims/tenantid",
allowedTenants
);
});
// Apply to all endpoints by default
options.DefaultPolicy = options.GetPolicy("AllowedTenantsOnly");
});
Filtro dei tenant basato sulla configurazione
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "your-api-client-id",
"AllowedTenants": [
"14c2f153-90a7-4689-9db7-9543bf084dad",
"af8cc1a0-d2aa-4ca7-b829-00d361edb652"
]
}
}
Avvio:
var allowedTenants = builder.Configuration.GetSection("AzureAd:AllowedTenants")
.Get<string[]>();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AllowedTenantsOnly", policyBuilder =>
{
policyBuilder.RequireClaim(
"http://schemas.microsoft.com/identity/claims/tenantid",
allowedTenants ?? Array.Empty<string>()
);
});
});
Combinato: Scope e filtro dei tenant
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("SecureApiAccess", policyBuilder =>
{
// Require specific scope
policyBuilder.RequireScope("access_as_user");
// AND require specific tenant
policyBuilder.RequireClaim(
"http://schemas.microsoft.com/identity/claims/tenantid",
allowedTenants
);
});
});
Procedure consigliate
Cose da fare
1. Nelle API Web usare [Authorize] sempre con la convalida dell'ambito:
[Authorize] // Authentication
[RequiredScope("access_as_user")] // Authorization
public class MyController : ControllerBase { }
2. Usare la configurazione per ambiti specifici dell'ambiente:
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
3. Applicare privilegi minimi:
[HttpGet]
[RequiredScope("read")] // Only read permission needed
[HttpPost]
[RequiredScope("write")] // Write permission for modifications
4. Usare i criteri per l'autorizzazione complessa:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy =>
{
policy.RequireScope("admin");
policy.RequireClaim("department", "IT");
});
});
5. Abilitare risposte di errore dettagliate nello sviluppo:
if (builder.Environment.IsDevelopment())
{
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
}
Cose da non fare
1. Non ignorare [Authorize] quando si usa RequiredScope:
// Wrong - RequiredScope won't work without [Authorize]
[RequiredScope("access_as_user")]
public class MyController : ControllerBase { }
// Correct
[Authorize]
[RequiredScope("access_as_user")]
public class MyController : ControllerBase { }
2. Non utilizzare gli ID tenant codificati in modo rigido nell'ambiente di produzione:
// Wrong
policyBuilder.RequireClaim("tid", "14c2f153-90a7-4689-9db7-9543bf084dad");
// Better - use configuration
var tenants = Configuration.GetSection("AllowedTenants").Get<string[]>();
policyBuilder.RequireClaim("tid", tenants);
3. Non confondere gli ambiti con i ruoli:
// Wrong - This checks roles claim, not scopes
[RequiredScope("Admin")] // "Admin" is typically a role, not a scope
// Correct
[RequiredScope("access_as_user")] // Scope
[Authorize(Roles = "Admin")] // Role
4. Non esporre informazioni sull'ambito sensibili nei messaggi di errore (produzione):
Configurare i livelli di registrazione e la gestione degli errori appropriati per gli ambienti di produzione.
Risoluzione dei problemi
403 Accesso vietato - Ambito mancante
Errore: L'API restituisce 403 anche con token valido.
Diagnosi:
- Decodificare il token in jwt.ms
- Verifica
scposcopeattestazione - Verificare che corrisponda all'attributo
RequiredScope
Soluzione:
- Assicurarsi che l'app client richieda l'ambito corretto durante l'acquisizione del token
- Verificare che l'ambito sia esposto nella registrazione dell'app per le API
- Concedere il consenso amministratore se necessario
RequiredScope non funziona
Sintomo: L'attributo sembra essere ignorato.
Controllare:
- Hai aggiunto l'attributo
[Authorize]? - Viene
app.UseAuthorization()chiamato dopoapp.UseAuthentication()? - È
services.AddAuthorization()registrato?
Chiave di configurazione non trovata
Errore: La convalida dell'ambito fallisce silenziosamente.
Controllare:
{
"AzureAd": {
"Scopes": "access_as_user" // Matches RequiredScopesConfigurationKey
}
}
Verificare che il percorso di configurazione corrisponda esattamente.