Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I den här artikeln implementerar du auktorisering i ASP.NET Core webb-API:er med hjälp av Microsoft. Identity.Web. Du validerar omfång (delegerade behörigheter) och appbehörigheter (programbehörigheter) för att kontrollera åtkomsten till skyddade resurser. I exemplen används Microsoft Entra ID som identitetsprovider.
Förstå auktoriseringsbegrepp
Det här avsnittet beskriver de viktigaste skillnaderna mellan autentisering och auktorisering och beskriver vad Microsoft. Identity.Web verifierar i åtkomsttoken.
Autentisering kontra auktorisering
| Begrepp | Avsikt | Result |
|---|---|---|
| autentisering | Verifiera identitet | 401 Obehörig om det misslyckas |
| Behörighet | Kontrollera behörigheter | 403 Förbjudet om otillräckligt |
Vad valideras
När ett webb-API tar emot en åtkomsttoken Microsoft. Identity.Web verifierar:
- Tokensignatur – kommer den från en betrodd utfärdare?
- Token-målgrupp – är den avsedd för det här API:et?
- Förfallodatum för token – är den fortfarande giltig?
- Omfång/roller – Har klientappen och användaren rätt behörigheter?
Den här guiden fokuserar på #4 – validering av omfång och appbehörigheter.
Omfång (delegerade behörigheter)
Omfång gäller när en användare delegerar behörighet till en app att agera för deras räkning (till exempel ett webb-API som anropas för en inloggad användares räkning).
| Detaljer | Värde |
|---|---|
| Tokenpåstående |
scp eller scope (klientapp); roles (användare) |
| Exempelvärden |
"access_as_user", "User.Read", "Files.ReadWrite" |
Appbehörigheter (programbehörigheter)
Appbehörigheter gäller när en app anropar webb-API:et som sig själv utan användarkontext, till exempel en daemon- eller bakgrundstjänst med klientautentiseringsuppgifter.
| Detaljer | Värde |
|---|---|
| Tokenpåstående | roles |
| Exempelvärden |
"Mail.Read.All", "User.Read.All" |
Verifiera omfång med RequiredScope
Attributet RequiredScope kontrollerar att åtkomsttoken innehåller minst ett av de angivna omfången. Använd det här attributet när ditt API endast hanterar användar delegerade begäranden.
Konfigurera omfångsverifiering
Följ de här stegen för att aktivera omfångsverifiering i ditt API.
1. Aktivera auktorisering i ditt API:
Lägg till autentiserings- och auktoriseringstjänster i din programpipeline:
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. Skydda styrenheter eller åtgärder:
Tillämpa attributen [Authorize] och [RequiredScope] på din kontrollant eller enskilda åtgärder:
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" });
}
}
Tillämpa omfångsmönster
Välj det mönster som passar bäst för hur du hanterar omfång i ditt program.
Mönster 1: Hårdkodade skop
Använd det här mönstret när omfången är fasta och kända vid utvecklingstillfället.
[Authorize]
[RequiredScope("access_as_user")]
public class TodoListController : ControllerBase
{
// All actions require "access_as_user" scope
}
Om du vill acceptera något av flera omfång anger du dem som parametrar:
[Authorize]
[RequiredScope("read", "write", "admin")]
public class TodoListController : ControllerBase
{
// Token must have "read" OR "write" OR "admin"
}
Mönster 2: Räckvidd från konfiguration
Använd det här mönstret när omfång ska vara konfigurerbara per miljö. Definiera omfången i konfigurationsfilen:
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "your-tenant-id",
"ClientId": "your-api-client-id",
"Scopes": "access_as_user read write"
}
}
Referera till konfigurationsnyckeln i kontrollanten:
[Authorize]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class TodoListController : ControllerBase
{
// Scopes read from configuration
}
Med den här metoden kan du ändra omfång utan att kompilera om.
Mönster 3: Omfång på åtgärdsnivå
Använd det här mönstret när olika åtgärder kräver olika behörigheter. Tillämpa [RequiredScope] på individuella metodaktioner:
[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();
}
}
Förstå valideringsflödet
När en begäran tas emot bearbetar mellanprogrammet den i följande ordning:
- ASP.NET Core mellanprogram för autentisering validerar token
-
RequiredScopekontrollerar attributet för kravetscpellerscope - Om en token innehåller minst ett matchande omfång fortsätter begäran.
- Om inget matchande omfång hittas returnerar API:et ett 403-förbjudet svar.
I följande exempel visas ett typiskt felsvar:
{
"error": "insufficient_scope",
"error_description": "The token does not have the required scope 'access_as_user'."
}
Verifiera appbehörigheter med RequiredScopeOrAppPermission
Attributet RequiredScopeOrAppPermission verifierar antingen omfång (delegerade) eller appbehörigheter (program). Använd det här attributet när ditt API hanterar både användardelegeringsappar och daemon-/tjänstappar från samma slutpunkt.
Om ditt API endast hanterar användar delegerade begäranden använder du RequiredScope i stället.
Konfigurera omfångs- eller appbehörighetsverifiering
Använd attributet för att acceptera någon av tokentyperna:
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);
}
}
Konfigurera appbehörigheter från inställningar
Lagra omfång och appbehörigheter i konfigurationen för att ändra dem utan att kompilera om.
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"
}
}
Referera till konfigurationsnycklarna i kontrollanten:
[Authorize]
[RequiredScopeOrAppPermission(
RequiredScopesConfigurationKey = "AzureAd:Scopes",
RequiredAppPermissionsConfigurationKey = "AzureAd:AppPermissions"
)]
public class TodoListController : ControllerBase
{
// Scopes and app permissions from configuration
}
Jämföra skillnader i tokenkrav
Följande tabell visar hur anspråk skiljer sig mellan användardelegering och endast apptoken:
| Tokentyp | Anspråk | Exempelvärde |
|---|---|---|
| Användardelegering |
scp eller scope |
"access_as_user User.Read" |
| Endast app | roles |
["TodoList.ReadWrite.All"] |
I följande exempel visas en användardelegeringstoken:
{
"aud": "api://your-api-client-id",
"iss": "https://login.microsoftonline.com/.../v2.0",
"scp": "access_as_user",
"sub": "user-object-id",
...
}
I följande exempel visas ett app-endast-token:
{
"aud": "api://your-api-client-id",
"iss": "https://login.microsoftonline.com/.../v2.0",
"roles": ["TodoList.ReadWrite.All"],
"sub": "app-object-id",
...
}
Skapa auktoriseringsprinciper
För komplexa auktoriseringsscenarier använder du ASP.NET Core auktoriseringsprinciper. Med principer kan du centralisera regler, kombinera flera krav och skriva testbar auktoriseringslogik.
| Förmån | Beskrivning |
|---|---|
| Centraliserad logik | Definiera auktoriseringsregler en gång, återanvänd överallt |
| Komponerbar | Kombinera flera krav (omfång + anspråk + anpassad logik) |
| Testbar | Det är enklare att enhetstesta auktoriseringslogik |
| Böjlig | Anpassade krav utöver omfångsverifiering |
Mönster 1: Definiera en policy med RequireScope
Definiera namngivna principer som kräver specifika omfång och referera sedan till dem på dina controllers:
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();
Tillämpa principerna på kontrollantåtgärder:
[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);
}
}
Mönster 2: Definiera en policy med ScopeAuthorizationRequirement
Använd ScopeAuthorizationRequirement för mer explicita omfångskrav:
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" })
);
});
});
Mönster 3: Ange en standardpolicy
Ange en standardprincip som gäller för alla [Authorize] attribut automatiskt:
builder.Services.AddAuthorization(options =>
{
var defaultPolicy = new AuthorizationPolicyBuilder()
.RequireScope("access_as_user")
.Build();
options.DefaultPolicy = defaultPolicy;
});
Varje [Authorize] attribut kräver nu omfånget access_as_user :
[Authorize] // Automatically requires "access_as_user" scope
public class TodoListController : ControllerBase
{
// All actions protected by default policy
}
Mönster 4: Kombinera flera krav
Kombinera omfångs-, roll- och autentiseringskrav i en enda princip:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminPolicy", policyBuilder =>
{
policyBuilder.RequireScope("admin");
policyBuilder.RequireRole("Admin"); // Also check role claim
policyBuilder.RequireAuthenticatedUser();
});
});
Mönster 5: Skapa en princip från konfigurationen
Läs in omfång från konfigurationen för att hålla principer miljöspecifika:
var requiredScopes = builder.Configuration["AzureAd:Scopes"]?.Split(' ');
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("ApiAccessPolicy", policyBuilder =>
{
if (requiredScopes != null)
{
policyBuilder.RequireScope(requiredScopes);
}
});
});
Filtrera begäranden efter klientorganisation
Begränsa API-åtkomst till token från specifika Microsoft Entra klienter. Detta är användbart när ditt API för flera klientorganisationer endast ska acceptera begäranden från godkända kundklientorganisationer.
Begränsa åtkomsten till tillåtna klienter
Definiera en princip som kontrollerar hyresgäst-ID-kravet mot en tillåten lista.
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");
});
Konfigurera klientfiltrering från inställningar
Lagra tillåtna hyresgäst-ID:n i konfigurationen för att hantera dem utan kodändringar.
appsettings.json:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "your-api-client-id",
"AllowedTenants": [
"14c2f153-90a7-4689-9db7-9543bf084dad",
"af8cc1a0-d2aa-4ca7-b829-00d361edb652"
]
}
}
Läs klientlistan och skapa regeln vid uppstart.
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>()
);
});
});
Kombinera omfång med hyresgästfiltrering
Skapa en princip som kräver både ett giltigt omfång och en godkänd klientorganisation:
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
);
});
});
Följ metodtipsen
Använd dessa rekommendationer för att skapa säker, underhållsbar auktoriseringslogik.
Saker att göra
1. Kombinera [Authorize] alltid med omfångsvalidering:
[Authorize] // Authentication
[RequiredScope("access_as_user")] // Authorization
public class MyController : ControllerBase { }
2. Använd konfiguration för miljöspecifika omfång:
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
3. Använd minst behörighet:
[HttpGet]
[RequiredScope("read")] // Only read permission needed
[HttpPost]
[RequiredScope("write")] // Write permission for modifications
4. Använd principer för komplex auktorisering:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy =>
{
policy.RequireScope("admin");
policy.RequireClaim("department", "IT");
});
});
5. Aktivera detaljerade felsvar under utveckling:
if (builder.Environment.IsDevelopment())
{
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
}
Förbud
1. Hoppa inte över [Authorize] när du använder 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. Hårdkoda inte klient-ID:t i produktion:
// Wrong
policyBuilder.RequireClaim("tid", "14c2f153-90a7-4689-9db7-9543bf084dad");
// Better - use configuration
var tenants = Configuration.GetSection("AllowedTenants").Get<string[]>();
policyBuilder.RequireClaim("tid", tenants);
3. Blanda inte ihop behörigheter med roller:
// 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. Exponera inte känslig omfångsinformation i produktionsfelmeddelanden:
Konfigurera lämpliga loggningsnivåer och felhantering för produktionsmiljöer.
Felsöka auktoriseringsproblem
Använd följande vägledning för att diagnostisera vanliga auktoriseringsproblem.
403 Förbjudet – omfång saknas
Fel: API returnerar 403 även med en giltig token.
Diagnos:
- Avkoda token på jwt.ms.
- Kontrollera anspråket
scpellerscope. - Kontrollera att värdet matchar attributet
RequiredScope.
Lösning:
- Se till att klientappen begär rätt omfång när en token erhålls.
- Kontrollera att omfånget exponeras i API-appregistreringen i Microsoft Entra.
- Bevilja administratörsmedgivande om det behövs.
RequiredScope fungerar inte
Symptom: Attributet verkar ignoreras.
Kontrollera följande:
- Har du lagt till attributet
[Authorize]? - Anropas
app.UseAuthorization()efterapp.UseAuthentication()? - Är
services.AddAuthorization()registrerad?
Konfigurationsnyckeln hittades inte
Fel: Omfångsvalidering misslyckas tyst.
Kontrollera följande:
{
"AzureAd": {
"Scopes": "access_as_user" // Matches RequiredScopesConfigurationKey
}
}
Kontrollera att konfigurationssökvägen matchar exakt.