Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Onder de dekkingen maken op rollen gebaseerde autorisatie en op claims gebaseerde autorisatie gebruik van een vereiste, een vereistehandler en een vooraf geconfigureerd beleid. Deze bouwstenen ondersteunen de expressie van autorisatie-evaluaties in code. Het resultaat is een uitgebreidere, herbruikbare, testbare autorisatiestructuur.
Een autorisatiebeleid bestaat uit een of meer vereisten. Registreer deze als onderdeel van de autorisatieserviceconfiguratie in het bestand van Program.cs
de app:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
});
In het voorgaande voorbeeld wordt een 'AtLeast21'-beleid gemaakt. Het heeft één vereiste: die van een minimumleeftijd, die als parameter aan de vereiste wordt verstrekt.
Installatie
De primaire service die bepaalt of de autorisatie is geslaagd, is IAuthorizationService:
/// <summary>
/// Checks policy based permissions for a user
/// </summary>
public interface IAuthorizationService
{
/// <summary>
/// Checks if a user meets a specific set of requirements for the specified resource
/// </summary>
/// <param name="user">The user to evaluate the requirements against.</param>
/// <param name="resource">
/// An optional resource the policy should be checked with.
/// If a resource is not required for policy evaluation you may pass null as the value
/// </param>
/// <param name="requirements">The requirements to evaluate.</param>
/// <returns>
/// A flag indicating whether authorization has succeeded.
/// This value is <value>true</value> when the user fulfills the policy;
/// otherwise <value>false</value>.
/// </returns>
/// <remarks>
/// Resource is an optional parameter and may be null. Please ensure that you check
/// it is not null before acting upon it.
/// </remarks>
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource,
IEnumerable<IAuthorizationRequirement> requirements);
/// <summary>
/// Checks if a user meets a specific authorization policy
/// </summary>
/// <param name="user">The user to check the policy against.</param>
/// <param name="resource">
/// An optional resource the policy should be checked with.
/// If a resource is not required for policy evaluation you may pass null as the value
/// </param>
/// <param name="policyName">The name of the policy to check against a specific
/// context.</param>
/// <returns>
/// A flag indicating whether authorization has succeeded.
/// Returns a flag indicating whether the user, and optional resource has fulfilled
/// the policy.
/// <value>true</value> when the policy has been fulfilled;
/// otherwise <value>false</value>.
/// </returns>
/// <remarks>
/// Resource is an optional parameter and may be null. Please ensure that you check
/// it is not null before acting upon it.
/// </remarks>
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user, object resource, string policyName);
}
De voorgaande code markeert de twee methoden van de IAuthorizationService.
IAuthorizationRequirement is een markeringsservice zonder methoden en tevens een mechanisme voor het bijhouden of de autorisatie succesvol is.
Elk IAuthorizationHandler is verantwoordelijk voor het controleren of aan de vereisten wordt voldaan:
/// <summary>
/// Classes implementing this interface are able to make a decision if authorization
/// is allowed.
/// </summary>
public interface IAuthorizationHandler
{
/// <summary>
/// Makes a decision if authorization is allowed.
/// </summary>
/// <param name="context">The authorization information.</param>
Task HandleAsync(AuthorizationHandlerContext context);
}
De AuthorizationHandlerContext klasse is wat de handler gebruikt om aan te geven of aan de vereisten is voldaan:
context.Succeed(requirement)
De volgende code toont de vereenvoudigde (en geannoteerde met opmerkingen) standaard implementatie van de autorisatieservice:
public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object resource, IEnumerable<IAuthorizationRequirement> requirements)
{
// Create a tracking context from the authorization inputs.
var authContext = _contextFactory.CreateContext(requirements, user, resource);
// By default this returns an IEnumerable<IAuthorizationHandler> from DI.
var handlers = await _handlers.GetHandlersAsync(authContext);
// Invoke all handlers.
foreach (var handler in handlers)
{
await handler.HandleAsync(authContext);
}
// Check the context, by default success is when all requirements have been met.
return _evaluator.Evaluate(authContext);
}
De volgende code toont een typische autorisatieserviceconfiguratie:
// Add all of your handlers to DI.
builder.Services.AddSingleton<IAuthorizationHandler, MyHandler1>();
// MyHandler2, ...
builder.Services.AddSingleton<IAuthorizationHandler, MyHandlerN>();
// Configure your policies
builder.Services.AddAuthorization(options =>
options.AddPolicy("Something",
policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything")));
Gebruik IAuthorizationService, [Authorize(Policy = "Something")]
of RequireAuthorization("Something")
voor autorisatie.
Beleid toepassen op MVC-controllers
Voor apps die Razor Pagina's gebruiken, zie de sectie Beleid toepassen op Razor Pagina's.
Beleidsregels toepassen op controllers met behulp van het [Authorize]
kenmerk met de beleidsnaam:
[Authorize(Policy = "AtLeast21")]
public class AtLeast21Controller : Controller
{
public IActionResult Index() => View();
}
Als er meerdere beleidsregels worden toegepast op het controller- en actieniveau, moeten alle beleidsregels aan voldaan worden voordat toegang wordt verleend.
[Authorize(Policy = "AtLeast21")]
public class AtLeast21Controller2 : Controller
{
[Authorize(Policy = "IdentificationValidated")]
public IActionResult Index() => View();
}
Beleid toepassen op Razor pagina's
Pas beleidsregels toe op Razor Pagina's met behulp van het [Authorize]
kenmerk met de beleidsnaam. Voorbeeld:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace AuthorizationPoliciesSample.Pages;
[Authorize(Policy = "AtLeast21")]
public class AtLeast21Model : PageModel { }
Beleidsregels kunnen niet worden toegepast op het niveau van de Razor Page handler; ze moeten worden toegepast op de Pagina.
Beleidsregels kunnen ook worden toegepast op Razor Pagina's met behulp van een autorisatieconventie.
Beleid toepassen op eindpunten
Pas beleidsregels toe op eindpunten met behulp van RequireAuthorization de beleidsnaam. Voorbeeld:
app.MapGet("/helloworld", () => "Hello World!")
.RequireAuthorization("AtLeast21");
Behoeften
Een autorisatievereiste is een verzameling gegevensparameters die een beleid kan gebruiken om de huidige gebruikersprincipaal te evalueren. In ons beleid 'AtLeast21' is de vereiste één parameter: de minimale leeftijd. Een vereiste implementeert IAuthorizationRequirement, wat een lege markeringsinterface is. Een geparameteriseerde minimale leeftijdsvereiste kan als volgt worden geïmplementeerd:
using Microsoft.AspNetCore.Authorization;
namespace AuthorizationPoliciesSample.Policies.Requirements;
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public MinimumAgeRequirement(int minimumAge) =>
MinimumAge = minimumAge;
public int MinimumAge { get; }
}
Als een autorisatiebeleid meerdere autorisatievereisten bevat, moeten alle vereisten worden voldaan zodat de beleidsevaluatie slaagt. Met andere woorden, meerdere autorisatievereisten die aan één autorisatiebeleid worden toegevoegd, worden behandeld op BASIS van AND .
Opmerking
Een vereiste hoeft geen gegevens of eigenschappen te hebben.
Autorisatie-behandelaars
Een autorisatiehandler is verantwoordelijk voor de evaluatie van de eigenschappen van een vereiste. De autorisatiehandler evalueert de vereisten op basis van een opgegeven AuthorizationHandlerContext om te bepalen of toegang is toegestaan.
Een vereiste kan meerdere handlers hebben. Een handler kan overnemen AuthorizationHandler<TRequirement>, waar TRequirement
is de vereiste die moet worden afgehandeld. Een handler kan ook rechtstreeks worden geïmplementeerd IAuthorizationHandler om meer dan één type vereiste af te handelen.
Een handler gebruiken voor één vereiste
In het volgende voorbeeld ziet u een een-op-een-relatie waarin een minimumleeftijdbeheerder een enkele vereiste afhandelt.
using System.Security.Claims;
using AuthorizationPoliciesSample.Policies.Requirements;
using Microsoft.AspNetCore.Authorization;
namespace AuthorizationPoliciesSample.Policies.Handlers;
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, MinimumAgeRequirement requirement)
{
var dateOfBirthClaim = context.User.FindFirst(
c => c.Type == ClaimTypes.DateOfBirth && c.Issuer == "http://contoso.com");
if (dateOfBirthClaim is null)
{
return Task.CompletedTask;
}
var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value);
int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
if (calculatedAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
De voorgaande code bepaalt of de huidige gebruikersprincipal een geboortedatumclaim heeft die is uitgegeven door een bekende en vertrouwde verlener. Autorisatie kan niet optreden wanneer de claim ontbreekt, in welk geval een voltooide taak wordt geretourneerd. Wanneer een claim aanwezig is, wordt de leeftijd van de gebruiker berekend. Als de gebruiker voldoet aan de minimumleeftijd die door de vereiste is gedefinieerd, wordt autorisatie als geslaagd beschouwd. Wanneer de autorisatie is geslaagd, context.Succeed
wordt aangeroepen met de vereiste als enige parameter.
Een handler gebruiken voor meerdere vereisten
In het volgende voorbeeld ziet u een een-op-veel-relatie waarin een machtigingshandler drie verschillende typen vereisten kan verwerken:
using System.Security.Claims;
using AuthorizationPoliciesSample.Policies.Requirements;
using Microsoft.AspNetCore.Authorization;
namespace AuthorizationPoliciesSample.Policies.Handlers;
public class PermissionHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (requirement is ReadPermission)
{
if (IsOwner(context.User, context.Resource)
|| IsSponsor(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
else if (requirement is EditPermission || requirement is DeletePermission)
{
if (IsOwner(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
}
return Task.CompletedTask;
}
private static bool IsOwner(ClaimsPrincipal user, object? resource)
{
// Code omitted for brevity
return true;
}
private static bool IsSponsor(ClaimsPrincipal user, object? resource)
{
// Code omitted for brevity
return true;
}
}
De voorgaande code gaat door PendingRequirements: een eigenschap met vereisten die niet als geslaagd zijn gemarkeerd. Voor een ReadPermission
vereiste moet de gebruiker een eigenaar of sponsor zijn om toegang te krijgen tot de aangevraagde resource. Voor een EditPermission
of DeletePermission
vereiste moeten ze eigenaar zijn om toegang te krijgen tot de aangevraagde resource.
Handlerregistratie
Registreer handlers in de serviceverzameling tijdens de configuratie. Voorbeeld:
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
De voorgaande code registreert MinimumAgeHandler
als een singleton. Handlers kunnen worden geregistreerd met behulp van een van de ingebouwde servicelifetimes.
Het is mogelijk om zowel een vereiste als een handler te bundelen in één klasse die zowel IAuthorizationRequirement als IAuthorizationHandler implementeert. Deze bundeling zorgt voor een strakke koppeling tussen de handler en de vereiste en wordt alleen aanbevolen voor eenvoudige vereisten en handlers. Als u een klasse maakt waarmee beide interfaces worden geïmplementeerd, hoeft u de handler niet meer te registreren in DI vanwege de ingebouwde PassThroughAuthorizationHandler functionaliteit waarmee de vereisten zelf kunnen worden verwerkt.
Bekijk de implementatie van de AssertionRequirement klasse voor een goed voorbeeld waarbij zowel AssertionRequirement een vereiste als de handler in een volledig zelfstandige klasse is.
Wat moet een handler retourneren?
Houd er rekening mee dat de Handle
methode in het handler-voorbeeld geen waarde retourneert. Hoe wordt een status van geslaagd of mislukt aangegeven?
Een handler geeft aan dat het lukt door aan te roepen
context.Succeed(IAuthorizationRequirement requirement)
, waarbij de vereiste wordt doorgegeven die is gevalideerd.Een handler hoeft over het algemeen geen fouten af te handelen, omdat andere handlers voor dezelfde vereiste kunnen slagen.
Om falen te garanderen, zelfs als andere vereiste-handlers slagen, roept u
context.Fail
aan.
Als een handler aanroept context.Succeed
of context.Fail
, worden alle andere handlers nog steeds aangeroepen. Hierdoor kunnen vereisten bijwerkingen produceren, zoals logboekregistratie, die zelfs plaatsvindt als een andere handler een vereiste heeft gevalideerd of mislukt. Wanneer ingesteld op false
, kortsluit de InvokeHandlersAfterFailure eigenschap de uitvoering van handlers wanneer context.Fail
wordt aangeroepen.
InvokeHandlersAfterFailure
wordt standaard op true
ingesteld, in dat geval worden alle handlers aangeroepen.
Opmerking
Autorisatie-handlers worden aangeroepen, zelfs als verificatie mislukt. Ook handlers kunnen in elke volgorde worden uitgevoerd, dus hangt er niet van af dat ze in een bepaalde volgorde worden aangeroepen.
Waarom wil ik meerdere handlers voor een vereiste?
In gevallen waarin u wilt evalueren op OR-basis , implementeert u meerdere handlers voor één vereiste. Microsoft heeft bijvoorbeeld deuren die alleen met sleutelkaarten worden geopend. Als u uw sleutelkaart thuis laat, drukt de receptioniste een tijdelijke sticker af en opent de deur voor u. In dit scenario hebt u één vereiste, BuildingEntry, maar meerdere handlers, die elk één vereiste onderzoeken.
BuildingEntryRequirement.cs
using Microsoft.AspNetCore.Authorization;
namespace AuthorizationPoliciesSample.Policies.Requirements;
public class BuildingEntryRequirement : IAuthorizationRequirement { }
BadgeEntryHandler.cs
using AuthorizationPoliciesSample.Policies.Requirements;
using Microsoft.AspNetCore.Authorization;
namespace AuthorizationPoliciesSample.Policies.Handlers;
public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(
c => c.Type == "BadgeId" && c.Issuer == "https://microsoftsecurity"))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
TemporaryStickerHandler.cs
using AuthorizationPoliciesSample.Policies.Requirements;
using Microsoft.AspNetCore.Authorization;
namespace AuthorizationPoliciesSample.Policies.Handlers;
public class TemporaryStickerHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(
c => c.Type == "TemporaryBadgeId" && c.Issuer == "https://microsoftsecurity"))
{
// Code to check expiration date omitted for brevity.
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
Zorg ervoor dat beide handlers zijn geregistreerd. Als een handler slaagt wanneer een beleid de BuildingEntryRequirement
evaluatie evalueert, slaagt de beleidsevaluatie.
Een func gebruiken om aan een beleid te voldoen
Er kunnen situaties zijn waarin het voldoen aan een beleid eenvoudig is om in code uit te drukken. Het is mogelijk om een Func<AuthorizationHandlerContext, bool>
op te geven bij het configureren van een beleid met de RequireAssertion
beleidsbouwer.
De vorige BadgeEntryHandler
kan bijvoorbeeld als volgt worden herschreven:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("BadgeEntry", policy =>
policy.RequireAssertion(context => context.User.HasClaim(c =>
(c.Type == "BadgeId" || c.Type == "TemporaryBadgeId")
&& c.Issuer == "https://microsoftsecurity")));
});
Toegang tot MVC-aanvraagcontext in handlers
De HandleRequirementAsync
methode heeft twee parameters: een AuthorizationHandlerContext
en de TRequirement
verwerking. Frameworks zoals MVC of SignalR kunnen vrijelijk elk object toevoegen aan de eigenschap op Resource
AuthorizationHandlerContext
om extra informatie door te geven.
Bij het gebruik van eindpuntroutering wordt autorisatie doorgaans verwerkt door de Authorization Middleware. In dit geval is de Resource
eigenschap een instantie van HttpContext. De context kan worden gebruikt voor toegang tot het huidige eindpunt, dat kan worden gebruikt om de onderliggende resource te testen waarnaar u doorsturen. Voorbeeld:
if (context.Resource is HttpContext httpContext)
{
var endpoint = httpContext.GetEndpoint();
var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
...
}
Bij traditionele routering of wanneer autorisatie plaatsvindt als onderdeel van het autorisatiefilter van MVC, is de waarde van Resource
een AuthorizationFilterContext exemplaar. Deze eigenschap biedt toegang tot HttpContext
, RouteData
en alles wat wordt geleverd door MVC en Razor Pages.
Het gebruik van de Resource
eigenschap is frameworkspecifiek. Als u informatie in de Resource
eigenschap gebruikt, beperkt u uw autorisatiebeleid tot bepaalde frameworks. Cast de Resource
eigenschap met behulp van het is
trefwoord en controleer of de cast is geslaagd om ervoor te zorgen dat uw code niet vastloopt met een InvalidCastException
uitvoering op andere frameworks:
// Requires the following import:
// using Microsoft.AspNetCore.Mvc.Filters;
if (context.Resource is AuthorizationFilterContext mvcContext)
{
// Examine MVC-specific things like routing data.
}
Globaal vereisen dat alle gebruikers worden geverifieerd
Zie Geverifieerde gebruikers vereisenvoor informatie over het globaal vereisen van verificatie van alle gebruikers.
Autorisatie met voorbeeld van externe service
De voorbeeldcode op AspNetCore.Docs.Samples laat zien hoe u aanvullende autorisatievereisten implementeert met een externe autorisatieservice. Het voorbeeldproject Contoso.API
wordt beveiligd met Azure AD. Een extra autorisatiecontrole van het Contoso.Security.API
project retourneert een nettolading die beschrijft of de Contoso.API
client-app de GetWeather
API kan aanroepen.
Het voorbeeld configureren
Maak een toepassingsregistratie in uw Microsoft Entra ID-tenant:
Wijs een AppRole toe.
Voeg onder API-machtigingen de AppRole toe als een machtiging en ververleent beheerderstoestemming. In deze installatie vertegenwoordigt deze app-registratie zowel de API als de client die de API aanroept. U kunt desgewenst twee app-registraties maken. Als u deze installatie gebruikt, moet u ervoor zorgen dat u alleen de API-machtigingen uitvoert, voegt u AppRole toe als een machtigingsstap voor alleen de client. Alleen voor de registratie van de client-app moet een clientgeheim worden gegenereerd.
Configureer het
Contoso.API
project met de volgende instellingen:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<Tenant name from AAD properties>.onmicrosoft.com",
"TenantId": "<Tenant Id from AAD properties>",
"ClientId": "<Client Id from App Registration representing the API>"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
- Configureer
Contoso.Security.API
met de volgende instellingen:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"AllowedClients": [
"<Use the appropriate Client Id representing the Client calling the API>"
]
}
Open het ContosoAPI.collection.json-bestand en configureer een omgeving met het volgende:
-
ClientId
: Client-id van app-registratie die de client vertegenwoordigt die de API aanroept. -
clientSecret
: Client Secret uit de app-registratie dat de client vertegenwoordigt die de API aanroept. -
TenantId
: Tenant-id van AAD-eigenschappen
-
Pak de opdrachten uit het
ContosoAPI.collection.json
bestand uit en gebruik ze om cURL-opdrachten te maken om de app te testen.Voer de oplossing uit en gebruik cURL om de API aan te roepen. U kunt onderbrekingspunten toevoegen in de
Contoso.Security.API.SecurityPolicyController
en observeren dat de client-id die wordt doorgegeven, gebruikt wordt om te controleren of het is toegestaan om het weer op te halen.
Aanvullende bronnen
Onder de dekkingen maken op rollen gebaseerde autorisatie en op claims gebaseerde autorisatie gebruik van een vereiste, een vereistehandler en een vooraf geconfigureerd beleid. Deze bouwstenen ondersteunen de expressie van autorisatie-evaluaties in code. Het resultaat is een uitgebreidere, herbruikbare, testbare autorisatiestructuur.
Een autorisatiebeleid bestaat uit een of meer vereisten. Deze wordt geregistreerd als onderdeel van de autorisatieserviceconfiguratie, in de Startup.ConfigureServices
methode:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
services.AddAuthorization(options =>
{
options.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
});
}
In het voorgaande voorbeeld wordt een 'AtLeast21'-beleid gemaakt. Het heeft één vereiste: die van een minimumleeftijd, die als parameter aan de vereiste wordt verstrekt.
Installatie
De primaire service die bepaalt of de autorisatie is geslaagd, is IAuthorizationService:
/// <summary>
/// Checks policy based permissions for a user
/// </summary>
public interface IAuthorizationService
{
/// <summary>
/// Checks if a user meets a specific set of requirements for the specified resource
/// </summary>
/// <param name="user">The user to evaluate the requirements against.</param>
/// <param name="resource">
/// An optional resource the policy should be checked with.
/// If a resource is not required for policy evaluation you may pass null as the value
/// </param>
/// <param name="requirements">The requirements to evaluate.</param>
/// <returns>
/// A flag indicating whether authorization has succeeded.
/// This value is <value>true</value> when the user fulfills the policy;
/// otherwise <value>false</value>.
/// </returns>
/// <remarks>
/// Resource is an optional parameter and may be null. Please ensure that you check
/// it is not null before acting upon it.
/// </remarks>
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource,
IEnumerable<IAuthorizationRequirement> requirements);
/// <summary>
/// Checks if a user meets a specific authorization policy
/// </summary>
/// <param name="user">The user to check the policy against.</param>
/// <param name="resource">
/// An optional resource the policy should be checked with.
/// If a resource is not required for policy evaluation you may pass null as the value
/// </param>
/// <param name="policyName">The name of the policy to check against a specific
/// context.</param>
/// <returns>
/// A flag indicating whether authorization has succeeded.
/// Returns a flag indicating whether the user, and optional resource has fulfilled
/// the policy.
/// <value>true</value> when the policy has been fulfilled;
/// otherwise <value>false</value>.
/// </returns>
/// <remarks>
/// Resource is an optional parameter and may be null. Please ensure that you check
/// it is not null before acting upon it.
/// </remarks>
Task<AuthorizationResult> AuthorizeAsync(
ClaimsPrincipal user, object resource, string policyName);
}
De voorgaande code markeert de twee methoden van de IAuthorizationService.
IAuthorizationRequirement is een markeringsservice zonder methoden en tevens een mechanisme voor het bijhouden of de autorisatie succesvol is.
Elk IAuthorizationHandler is verantwoordelijk voor het controleren of aan de vereisten wordt voldaan:
/// <summary>
/// Classes implementing this interface are able to make a decision if authorization
/// is allowed.
/// </summary>
public interface IAuthorizationHandler
{
/// <summary>
/// Makes a decision if authorization is allowed.
/// </summary>
/// <param name="context">The authorization information.</param>
Task HandleAsync(AuthorizationHandlerContext context);
}
De AuthorizationHandlerContext klasse is wat de handler gebruikt om aan te geven of aan de vereisten is voldaan:
context.Succeed(requirement)
De volgende code toont de vereenvoudigde (en geannoteerde met opmerkingen) standaard implementatie van de autorisatieservice:
public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
object resource, IEnumerable<IAuthorizationRequirement> requirements)
{
// Create a tracking context from the authorization inputs.
var authContext = _contextFactory.CreateContext(requirements, user, resource);
// By default this returns an IEnumerable<IAuthorizationHandlers> from DI.
var handlers = await _handlers.GetHandlersAsync(authContext);
// Invoke all handlers.
foreach (var handler in handlers)
{
await handler.HandleAsync(authContext);
}
// Check the context, by default success is when all requirements have been met.
return _evaluator.Evaluate(authContext);
}
De volgende code toont een typische ConfigureServices
code:
public void ConfigureServices(IServiceCollection services)
{
// Add all of your handlers to DI.
services.AddSingleton<IAuthorizationHandler, MyHandler1>();
// MyHandler2, ...
services.AddSingleton<IAuthorizationHandler, MyHandlerN>();
// Configure your policies
services.AddAuthorization(options =>
options.AddPolicy("Something",
policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything")));
services.AddControllersWithViews();
services.AddRazorPages();
}
Gebruik IAuthorizationService of [Authorize(Policy = "Something")]
voor autorisatie.
Beleid toepassen op MVC-controller
Als u Razor Pagina's gebruikt, zie Beleid toepassen voor Razor Pagina's in dit document.
Beleidsregels worden toegepast op controllers met behulp van het [Authorize]
kenmerk met de beleidsnaam. Voorbeeld:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[Authorize(Policy = "AtLeast21")]
public class AlcoholPurchaseController : Controller
{
public IActionResult Index() => View();
}
Beleid toepassen op Razor pagina's
Beleidsregels worden toegepast op Razor Pagina's met behulp van het [Authorize]
kenmerk met de beleidsnaam. Voorbeeld:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
[Authorize(Policy = "AtLeast21")]
public class AlcoholPurchaseModel : PageModel
{
}
Beleidsregels kunnen niet worden toegepast op het niveau van de Razor Page handler; ze moeten worden toegepast op de Pagina.
Beleidsregels kunnen worden toegepast op Razor Pagina's met behulp van een autorisatieconventie.
Behoeften
Een autorisatievereiste is een verzameling gegevensparameters die een beleid kan gebruiken om de huidige gebruikersprincipaal te evalueren. In ons beleid 'AtLeast21' is de vereiste één parameter: de minimale leeftijd. Een vereiste implementeert IAuthorizationRequirement, wat een lege markeringsinterface is. Een geparameteriseerde minimale leeftijdsvereiste kan als volgt worden geïmplementeerd:
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public int MinimumAge { get; }
public MinimumAgeRequirement(int minimumAge)
{
MinimumAge = minimumAge;
}
}
Als een autorisatiebeleid meerdere autorisatievereisten bevat, moeten alle vereisten worden voldaan zodat de beleidsevaluatie slaagt. Met andere woorden, meerdere autorisatievereisten die aan één autorisatiebeleid worden toegevoegd, worden behandeld op BASIS van AND .
Opmerking
Een vereiste hoeft geen gegevens of eigenschappen te hebben.
Autorisatie-behandelaars
Een autorisatiehandler is verantwoordelijk voor de evaluatie van de eigenschappen van een vereiste. De autorisatiehandler evalueert de vereisten op basis van een opgegeven AuthorizationHandlerContext om te bepalen of toegang is toegestaan.
Een vereiste kan meerdere handlers hebben. Een handler kan overnemen AuthorizationHandler<TRequirement>, waar TRequirement
is de vereiste die moet worden afgehandeld. Een handler kan ook implementeren IAuthorizationHandler om meer dan één type vereiste af te handelen.
Een handler gebruiken voor één vereiste
In het volgende voorbeeld ziet u een een-op-een-relatie waarin een minimumleeftijdverwerker één vereiste gebruikt.
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
MinimumAgeRequirement requirement)
{
if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth &&
c.Issuer == "http://contoso.com"))
{
//TODO: Use the following if targeting a version of
//.NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
var dateOfBirth = Convert.ToDateTime(
context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth &&
c.Issuer == "http://contoso.com").Value);
int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
if (calculatedAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
//TODO: Use the following if targeting a version of
//.NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
}
De voorgaande code bepaalt of de huidige gebruikersprincipal een geboortedatumclaim heeft die is uitgegeven door een bekende en vertrouwde verlener. Autorisatie kan niet optreden wanneer de claim ontbreekt, in welk geval een voltooide taak wordt geretourneerd. Wanneer een claim aanwezig is, wordt de leeftijd van de gebruiker berekend. Als de gebruiker voldoet aan de minimumleeftijd die door de vereiste is gedefinieerd, wordt autorisatie als geslaagd beschouwd. Wanneer de autorisatie is geslaagd, context.Succeed
wordt aangeroepen met de vereiste als enige parameter.
Een handler gebruiken voor meerdere vereisten
In het volgende voorbeeld ziet u een een-op-veel-relatie waarin een machtigingshandler drie verschillende typen vereisten kan verwerken:
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;
public class PermissionHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
var pendingRequirements = context.PendingRequirements.ToList();
foreach (var requirement in pendingRequirements)
{
if (requirement is ReadPermission)
{
if (IsOwner(context.User, context.Resource) ||
IsSponsor(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
else if (requirement is EditPermission ||
requirement is DeletePermission)
{
if (IsOwner(context.User, context.Resource))
{
context.Succeed(requirement);
}
}
}
//TODO: Use the following if targeting a version of
//.NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
private bool IsOwner(ClaimsPrincipal user, object resource)
{
// Code omitted for brevity
return true;
}
private bool IsSponsor(ClaimsPrincipal user, object resource)
{
// Code omitted for brevity
return true;
}
}
De voorgaande code gaat door PendingRequirements: een eigenschap met vereisten die niet als geslaagd zijn gemarkeerd. Voor een ReadPermission
vereiste moet de gebruiker een eigenaar of sponsor zijn om toegang te krijgen tot de aangevraagde resource. Voor een EditPermission
of DeletePermission
vereiste moet de gebruiker de eigenaar zijn om toegang te krijgen tot de aangevraagde resource.
Handlerregistratie
Handlers worden geregistreerd in de dienstencollectie tijdens het configuratieproces. Voorbeeld:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
services.AddAuthorization(options =>
{
options.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
});
services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
}
De voorgaande code registreert MinimumAgeHandler
als een singleton door services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
aan te roepen. Handlers kunnen worden geregistreerd met behulp van een van de ingebouwde servicelifetimes.
Het is mogelijk om zowel een vereiste als een handler te bundelen in één klasse die zowel IAuthorizationRequirement als IAuthorizationHandler implementeert. Deze bundeling zorgt voor een strakke koppeling tussen de handler en de vereiste en wordt alleen aanbevolen voor eenvoudige vereisten en handlers. Als u een klasse maakt waarmee beide interfaces worden geïmplementeerd, hoeft u de handler niet meer te registreren in DI vanwege de ingebouwde PassThroughAuthorizationHandler waarmee vereisten zelf kunnen worden afgehandeld.
Zie de AssertionRequirement-klasse voor een goed voorbeeld waarbij zowel AssertionRequirement
een vereiste als de handler in een volledig zelfstandige klasse is.
Wat moet een handler retourneren?
Houd er rekening mee dat de Handle
methode in het handler-voorbeeld geen waarde retourneert. Hoe wordt een status van geslaagd of mislukt aangegeven?
Een handler geeft aan dat het lukt door aan te roepen
context.Succeed(IAuthorizationRequirement requirement)
, waarbij de vereiste wordt doorgegeven die is gevalideerd.Een handler hoeft over het algemeen geen fouten af te handelen, omdat andere handlers voor dezelfde vereiste kunnen slagen.
Om falen te garanderen, zelfs als andere vereiste-handlers slagen, roept u
context.Fail
aan.
Als een handler aanroept context.Succeed
of context.Fail
, worden alle andere handlers nog steeds aangeroepen. Hierdoor kunnen vereisten bijwerkingen produceren, zoals logboekregistratie, die zelfs plaatsvindt als een andere handler een vereiste heeft gevalideerd of mislukt. Wanneer ingesteld op false
, kortsluit de InvokeHandlersAfterFailure eigenschap de uitvoering van handlers wanneer context.Fail
wordt aangeroepen.
InvokeHandlersAfterFailure
wordt standaard op true
ingesteld, in dat geval worden alle handlers aangeroepen.
Opmerking
Autorisatie-handlers worden aangeroepen, zelfs als verificatie mislukt.
Waarom wil ik meerdere handlers voor een vereiste?
In gevallen waarin u wilt evalueren op OR-basis , implementeert u meerdere handlers voor één vereiste. Microsoft heeft bijvoorbeeld deuren die alleen met sleutelkaarten worden geopend. Als u uw sleutelkaart thuis laat, drukt de receptioniste een tijdelijke sticker af en opent de deur voor u. In dit scenario hebt u één vereiste, BuildingEntry, maar meerdere handlers, die elk één vereiste onderzoeken.
BuildingEntryRequirement.cs
using Microsoft.AspNetCore.Authorization;
public class BuildingEntryRequirement : IAuthorizationRequirement
{
}
BadgeEntryHandler.cs
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;
public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(c => c.Type == "BadgeId" &&
c.Issuer == "http://microsoftsecurity"))
{
context.Succeed(requirement);
}
//TODO: Use the following if targeting a version of
//.NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
}
TemporaryStickerHandler.cs
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;
public class TemporaryStickerHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(c => c.Type == "TemporaryBadgeId" &&
c.Issuer == "https://microsoftsecurity"))
{
// We'd also check the expiration date on the sticker.
context.Succeed(requirement);
}
//TODO: Use the following if targeting a version of
//.NET Framework older than 4.6:
// return Task.FromResult(0);
return Task.CompletedTask;
}
}
Zorg ervoor dat beide handlers zijn geregistreerd. Als een handler slaagt wanneer een beleid de BuildingEntryRequirement
evaluatie evalueert, slaagt de beleidsevaluatie.
Een func gebruiken om aan een beleid te voldoen
Er kunnen situaties zijn waarin het voldoen aan een beleid eenvoudig is om in code uit te drukken. Het is mogelijk om een Func<AuthorizationHandlerContext, bool>
beleid op te geven bij het configureren van uw beleid met de RequireAssertion
beleidsbouwer.
De vorige BadgeEntryHandler
kan bijvoorbeeld als volgt worden herschreven:
services.AddAuthorization(options =>
{
options.AddPolicy("BadgeEntry", policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(c =>
(c.Type == "BadgeId" ||
c.Type == "TemporaryBadgeId") &&
c.Issuer == "https://microsoftsecurity")));
});
Toegang tot MVC-aanvraagcontext in handlers
De HandleRequirementAsync
methode die u in een autorisatiehandler implementeert, heeft twee parameters: een AuthorizationHandlerContext
en de TRequirement
die u verwerkt. Frameworks zoals MVC of SignalR kunnen vrijelijk elk object toevoegen aan de eigenschap op Resource
AuthorizationHandlerContext
om extra informatie door te geven.
Bij het gebruik van eindpuntroutering wordt autorisatie doorgaans verwerkt door de Authorization Middleware. In dit geval is de Resource
eigenschap een instantie van HttpContext. De context kan worden gebruikt voor toegang tot het huidige eindpunt, dat kan worden gebruikt om de onderliggende resource te testen waarnaar u doorsturen. Voorbeeld:
if (context.Resource is HttpContext httpContext)
{
var endpoint = httpContext.GetEndpoint();
var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
...
}
Bij traditionele routering of wanneer autorisatie plaatsvindt als onderdeel van het autorisatiefilter van MVC, is de waarde van Resource
een AuthorizationFilterContext exemplaar. Deze eigenschap biedt toegang tot HttpContext
, RouteData
en alles wat wordt geleverd door MVC en Razor Pages.
Het gebruik van de Resource
eigenschap is frameworkspecifiek. Als u informatie in de Resource
eigenschap gebruikt, beperkt u uw autorisatiebeleid tot bepaalde frameworks. Cast de Resource
eigenschap met behulp van het is
trefwoord en controleer of de cast is geslaagd om ervoor te zorgen dat uw code niet vastloopt met een InvalidCastException
uitvoering op andere frameworks:
// Requires the following import:
// using Microsoft.AspNetCore.Mvc.Filters;
if (context.Resource is AuthorizationFilterContext mvcContext)
{
// Examine MVC-specific things like routing data.
}
Globaal vereisen dat alle gebruikers worden geverifieerd
Zie Geverifieerde gebruikers vereisenvoor informatie over het globaal vereisen van verificatie van alle gebruikers.