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.
Een ASP.NET Core-autorisatiebeleid is een benoemde set met een of meer autorisatievereisten die door het framework worden geëvalueerd om te bepalen of een gebruiker toegang heeft tot een resource.
In dit artikel worden het volgende uitgelegd:
- Hoe u vereisten opstelt.
- Hoe u beleid registreert en toepast.
- Autorisatiehandlers voor evaluatie van één en meerdere vereisten.
- Hoe meerdere vereisten in één beleid worden geëvalueerd.
In de praktijk wordt een beleid toegepast met [Authorize(Policy = "...")] (Razor onderdelen, pagina's en controllers) of RequireAuthorization(...) (eindpunten) en het framework maakt gebruik van handlers om de vereisten achter een beleid te evalueren.
IAuthorizationPolicyProvider(Aangepaste autorisatiebeleidsproviders in ASP.NET Core documentatie) genereert dynamisch beleid in plaats van ze te registreren bij het opstarten van de app.
Op rollen gebaseerde autorisatie en op claims gebaseerde autorisatie maken gebruik van een vereiste, een vereistehandler en een vooraf geconfigureerd autorisatiebeleid. Deze bouwstenen ondersteunen de expressie van autorisatie-evaluaties in code.
In dit artikel worden voorbeelden van Razor-onderdelen gebruikt en is gericht op Blazor autorisatiescenario's voor ASP.NET Core 3.1 of hoger. Zie Razor de volgende bronnen na het lezen van dit artikel voor pagina's en MVC-richtlijnen die van toepassing zijn op alle releases van ASP.NET Core:
- Autorisatie op basis van beleid in ASP.NET Core Razor Pagina's
- Autorisatie op basis van beleid in ASP.NET Core MVC
In sommige voorbeelden in dit artikel (ASP.NET Core 8.0 of hoger) worden primaire constructors gebruikt, beschikbaar in C# 12 (.NET 8) of hoger. Zie Primaire constructors declareren voor klassen en structs (C#-documentatie) en Primaire constructors (C#-handleiding) voor meer informatie.
Vereisten en registratie van beleid
Een autorisatiebeleid bestaat uit een of meer vereisten die door een beleid worden gebruikt om autorisatie voor de huidige gebruikersprincipaal te evalueren. Een vereiste implementeert IAuthorizationRequirement, wat een lege markeringsinterface is.
Wanneer een vereiste geen gegevens bevat of eigenschappen (parameters) bevat, fungeert deze als een lege markering om een gekoppelde autorisatiehandler (IAuthorizationHandler) te activeren voor de verwerking van autorisatie (zie verderop in dit artikel). Omdat de handler in dit geval volledig afhankelijk is van de HTTP-context, gebruikersclaims of back-endgegevens om een beslissing te nemen over de gebruiker die aan de vereiste voldoet, vereist de vereisteklasse zelf geen interne gegevens of parameters. De eis geeft het framework alleen aan welke regel het moet evalueren.
Denk bijvoorbeeld aan de volgende minimale leeftijdsvereiste (MinimumAgeRequirement), die alleen als een markeringsklasse wordt geïmplementeerd:
public class MinimumAgeRequirement : IAuthorizationRequirement { }
De voorgaande vereiste wordt gebruikt om een beleid te maken waarmee wordt bevestigd dat de gebruiker ouder is dan de leeftijd waarop de handler controleert. Een AuthorizationHandler<MinimumAgeRequirement> inspecteert de AuthorizationHandlerContext.User. Als de gebruiker een geboortedatumclaim heeft die aangeeft dat deze ouder is dan een bepaalde leeftijd, slaagt de vereiste. Voor het vereisteobject zijn in dit geval geen eigenschappen (parameters) vereist. In het volgende voorbeeld ziet u de volledige implementatie van een minimale leeftijdsvereiste met een parameter voor het instellen van de minimumleeftijd.
Houd rekening met de volgende MinimumAgeRequirement vereiste, waarin één parameter, een minimale leeftijd, wordt beschreven om te evalueren op gebruikersautorisatie:
using Microsoft.AspNetCore.Authorization;
namespace BlazorWebAppAuthorization.Policies.Requirements;
public class MinimumAgeRequirement(int minimumAge) : IAuthorizationRequirement
{
public int MinimumAge { get; } = minimumAge;
}
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public MinimumAgeRequirement(int minimumAge) =>
MinimumAge = minimumAge;
public int MinimumAge { get; }
}
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public int MinimumAge { get; }
public MinimumAgeRequirement(int minimumAge)
{
MinimumAge = minimumAge;
}
}
Een beleid wordt geregistreerd als onderdeel van de configuratie van de autorisatieservice in het bestand van Program de app door aan te roepen AuthorizationBuilder.AddPolicy. In het volgende voorbeeld wordt een AtLeast21 beleid gemaakt met één vereiste van een minimumleeftijd en wordt de minimumleeftijd ingesteld op 21 jaar oud.
builder.Services.AddAuthorizationBuilder()
.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
Een beleid wordt geregistreerd als onderdeel van de configuratie van de autorisatieservice in het bestand van Program de app door aan te roepen AuthorizationBuilder.AddPolicy. In het volgende voorbeeld wordt een AtLeast21 beleid gemaakt met één vereiste van een minimumleeftijd en wordt de minimumleeftijd ingesteld op 21 jaar oud:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
});
Een beleid wordt geregistreerd als onderdeel van de autorisatieserviceconfiguratie in Startup.ConfigureServices (Startup.cs) door aan te roepen AuthorizationBuilder.AddPolicy. In het volgende voorbeeld wordt een AtLeast21 beleid gemaakt met één vereiste van een minimumleeftijd en wordt de minimumleeftijd ingesteld op 21 jaar oud:
services.AddAuthorization(options =>
{
options.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
});
Als een autorisatiebeleid meerdere autorisatievereisten bevat, moet aan alle vereisten worden voldaan voordat de evaluatie van het beleid slaagt. Met andere woorden, meerdere autorisatievereisten die aan één autorisatiebeleid worden toegevoegd, worden behandeld op BASIS van AND .
Beleid toepassen op Razor onderdelen
Beleidsregels toepassen op Razor onderdelen met behulp van het [Authorize] kenmerk met de beleidsnaam:
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "CustomerServiceMember")]
Als er meerdere beleidsregels worden toegepast, moeten alle beleidsregels worden doorgegeven voordat toegang wordt verleend:
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "CustomerServiceMember")]
@attribute [Authorize(Policy = "HumanResourcesMember")]
Beleid toepassen op eindpunten
Pas beleidsregels toe op eindpunten met behulp van RequireAuthorization de beleidsnaam. Voorbeeld:
app.MapGet("/helloworld", () => "Hello World!")
.RequireAuthorization("AtLeast21");
Beleidsregels toepassen in MVC- en Razor Pages-apps
Zie de volgende bronnen voor hulp bij het toepassen van beleid in Razor Pagina's en MVC-apps:
- Autorisatie op basis van beleid in ASP.NET Core Razor Pagina's
- Autorisatie op basis van beleid in ASP.NET Core MVC
Autorisatieservice-interface (IAuthorizationService)
IAuthorizationService is voornamelijk verantwoordelijk voor het bepalen of de autorisatie is geslaagd wanneer een IAuthorizationService.AuthorizeAsync-overload wordt aangeroepen:
-
AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements): Controleert of een gebruiker voldoet aan een specifieke set autorisatievereisten voor een opgegeven resource. -
AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName): Controleert of een gebruiker voldoet aan een specifiek autorisatiebeleid voor een opgegeven resource.
Als een resource niet is vereist voor beleidsevaluatie, wordt null doorgegeven voor de resource.
De voorgaande methoden retourneren een in een AuthorizationResult verpakte Task.
Elk IAuthorizationHandler is verantwoordelijk voor het controleren of aan de vereisten wordt voldaan via IAuthorizationHandler.HandleAsync. De AuthorizationHandlerContext klasse bevat de autorisatie-informatie die wordt gebruikt door de IAuthorizationHandler implementatie. IAuthorizationRequirement is een markeringsinterface zonder methoden die dienen als mechanisme voor het bijhouden of autorisatie is geslaagd. Wanneer AuthorizationHandlerContext.Succeed wordt aangeroepen met de IAuthorizationRequirement, wordt voldaan aan het beleid:
context.Succeed(requirement);
Autorisatiehandlers
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 access is toegestaan.
Een vereiste kan meerdere handlers hebben. Een handler kan overnemen AuthorizationHandler<TRequirement>, waar TRequirement is de vereiste om te verwerken. Een handler kan er ook voor kiezen om IAuthorizationHandler direct te implementeren om meer dan één type vereisten 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 Microsoft.AspNetCore.Authorization;
using BlazorWebAppAuthorization.Policies.Requirements;
namespace BlazorWebAppAuthorization.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);
if (dateOfBirthClaim is null)
{
return Task.CompletedTask;
}
var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value);
var calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
if (calculatedAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, MinimumAgeRequirement requirement)
{
var dateOfBirthClaim =
context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth);
if (dateOfBirthClaim is null)
{
return Task.CompletedTask;
}
var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value);
var calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
if (calculatedAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
MinimumAgeRequirement requirement)
{
if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth))
{
// 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).Value);
var calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
{
calculatedAge--;
}
if (calculatedAge >= requirement.MinimumAge)
{
context.Succeed(requirement);
}
// 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. 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 Microsoft.AspNetCore.Authorization;
using BlazorWebAppAuthorization.Policies.Requirements;
namespace BlazorWebAppAuthorization.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;
}
}
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
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);
}
}
}
// 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 vereiste van ReadPermission moet de gebruiker eigenaar of sponsor zijn om de aangevraagde resource te access. Voor een EditPermission-vereiste of DeletePermission-vereiste moeten ze eigenaar zijn om toegang te krijgen tot de aangevraagde resource.
Handlerregistratie
Registreer handlers in de serviceverzameling tijdens de configuratie. In het volgende voorbeeld wordt een minimumleeftijd-handler (MinimumAgeHandler) geregistreerd als een singleton-service, maar een handler kan worden geregistreerd met een van de ingebouwde servicelifetimes:
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
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 die beide interfaces implementeert, hoeft u de handler niet meer te registreren in de servicecontainer vanwege de ingebouwde PassThroughAuthorizationHandler functionaliteit waarmee vereisten zelf kunnen worden verwerkt.
Zie de implementatie van de ASP.NET Core-klasse AssertionRequirement voor een voorbeeld waarin zowel AssertionRequirement een vereiste als de handler in een volledig zelfstandige klasse is. Met de API van het AssertionRequirement framework kunt u toegang valideren met behulp van inline lambda-expressies in plaats van afzonderlijke, standaardvereisten en handlerklassen te schrijven.
Note
Documentatiekoppelingen naar .NET-referentiebron laden meestal de standaardbranch van de opslagplaats, die de huidige ontwikkeling vertegenwoordigt voor de volgende release van .NET. Als u een tag voor een specifieke release wilt selecteren, gebruikt u de Switch branches of tags vervolgkeuzelijst. Zie Het selecteren van een versietag van ASP.NET Core broncode (dotnet/AspNetCore.Docs #26205) voor meer informatie.
Wat moet een handler retourneren?
De Handle methode in het handler-voorbeeld retourneert geen waarde. Hoe wordt een status van geslaagd of mislukt aangegeven?
Een handler geeft aan dat het lukt door aan te roepen
context.Succeed, waarbij de gevalideerde vereiste (IAuthorizationRequirement) wordt doorgegeven.Een handler is niet vereist voor het afhandelen van fouten in het algemeen, omdat andere handlers voor dezelfde vereiste kunnen slagen.
Om falen te garanderen, zelfs als andere vereiste-handlers slagen, roept u
context.Failaan.
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.
Note
Autorisatie-handlers worden aangeroepen, zelfs als verificatie mislukt. Ook handlers kunnen in elke volgorde worden uitgevoerd, dus niet afhankelijk van de volgorde van aanroepende handlers.
Waarom wil ik meerdere handlers voor een vereiste?
In gevallen waarin u wilt evalueren op OR-basis , implementeert u meerdere handlers voor één vereiste. Stel dat contoso corporation deuren heeft 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 heeft de app één vereiste, maar meerdere handlers, die elk één vereiste onderzoeken.
In de volgende voorbeeld-implementaties:
-
BuildingEntryRequirementis de vereiste om het gebouw binnen te gaan. -
BadgeEntryHandler(de persoon heeft een badge) enTemporaryStickerHandler(de persoon heeft een tijdelijke sticker) zijn afzonderlijke handlers, die elk één vereiste onderzoeken.
BuildingEntryRequirement.cs:
using Microsoft.AspNetCore.Authorization;
namespace BlazorWebAppAuthorization.Policies.Requirements;
public class BuildingEntryRequirement : IAuthorizationRequirement { }
BadgeEntryHandler.cs:
using Microsoft.AspNetCore.Authorization;
using BlazorWebAppAuthorization.Policies.Requirements;
namespace BlazorWebAppAuthorization.Policies.Handlers;
public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context, BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(c => c.Type == "BadgeId"))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
TemporaryStickerHandler.cs:
using Microsoft.AspNetCore.Authorization;
using BlazorWebAppAuthorization.Policies.Requirements;
namespace BlazorWebAppAuthorization.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://contososecurity"))
{
// Code to check expiration date omitted for brevity.
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
BuildingEntryRequirement.cs:
using Microsoft.AspNetCore.Authorization;
public class BuildingEntryRequirement : IAuthorizationRequirement
{
}
BadgeEntryHandler.cs:
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(c =>
c.Type == "BadgeId" &&
c.Issuer == "https://contososecurity"))
{
context.Succeed(requirement);
}
// 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.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
public class TemporaryStickerHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
BuildingEntryRequirement requirement)
{
if (context.User.HasClaim(c =>
c.Type == "TemporaryBadgeId" &&
c.Issuer == "https://contososecurity"))
{
// We'd also check the expiration date on the sticker.
context.Succeed(requirement);
}
// 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 van beide afhandelaars slaagt wanneer een beleid de BuildingEntryRequirement evalueert, slaagt de evaluatie van het beleid.
Gebruik Func om aan een beleid te voldoen
Er zijn situaties waarin het eenvoudig is om in code uit te drukken dat aan een beleid wordt voldaan met een Func<AuthorizationHandlerContext, bool> delegate bij het configureren van een beleid met de RequireAssertion policy builder. Het voorgaande BadgeEntryHandler kan bijvoorbeeld als volgt worden herschreven:
options.AddPolicy("AtLeast21", policy =>
policy.Requirements.Add(new MinimumAgeRequirement(21)));
(c.Type == "BadgeId" || c.Type == "TemporaryBadgeId")
&& c.Issuer == "https://contososecurity")));
});
// <snippet_minimumAgeHandlerRegistration>
services.AddAuthorization(options =>
{
options.AddPolicy("BadgeEntry", policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(c =>
(c.Type == "BadgeId" ||
c.Type == "TemporaryBadgeId") &&
c.Issuer == "https://microsoftsecurity")));
});
Globale gebruikersverificatie vereisen
Zie Maak een ASP.NET Core-app met gebruikersgegevens die zijn beveiligd door autorisatie voor meer informatie over het vereisen van verificatie voor alle app-gebruikers.
Autorisatie via een voorbeeld van een externe service
De autorisatie via een voorbeeld van een externe service (dotnet/AspNetCore.Docs.SamplesGitHub opslagplaats) laat zien hoe u aanvullende autorisatievereisten implementeert met een externe autorisatieservice. Het project van Contoso.API de oplossing wordt beveiligd met Microsoft Entra ID. Een extra autorisatiecontrole van het Contoso.Security.API-project retourneert gegevens die beschrijven of de Contoso.API client-app de GetWeather-API kan aanroepen.
Het voorbeeld configureren
De volgende demonstratie is afhankelijk van het gebruik van NSwag (Swagger/OpenAPI) of cURL in een opdrachtshell.
Stel in het Contoso.Security.API-project de plaatsaanduiding AllowedClients ({CLIENT ID}) in op een willekeurige test-GUID-waarde (bijvoorbeeld 00001111-aaaa-2222-bbbb-3333cccc4444):
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"AllowedClients": [
"{CLIENT ID (FOR THE CLIENT CALLING CONTOSO.API)}"
]
}
Gebruik in een opdrachtshell die is geopend voor het project Contoso.APIdotnet user-jwts om een toegangstoken te genereren met een appid-claim voor de ID van de client-app, die in de vorige stap is gemaakt (bijvoorbeeld 00001111-aaaa-2222-bbbb-3333cccc4444).
dotnet user-jwts create --claim appid={GUID}
Voorbeeld:
dotnet user-jwts create --claim appid=00001111-aaaa-2222-bbbb-3333cccc4444
De uitvoer produceert een token na 'Token:' in de opdrachtshell:
New JWT saved with ID '{JWT ID}'.
Name: {USER}
Custom Claims: [appid=00001111-aaaa-2222-bbbb-3333cccc4444]
Token: {TOKEN}
Leg de waarde van het token apart (waarbij de {TOKEN} tijdelijke aanduiding wordt weergegeven in de voorgaande uitvoer) voor later gebruik.
U kunt het token decoderen in een online JWT decoder, bijvoorbeeld jwt.ms om de inhoud ervan weer te geven en te laten zien dat het een appid claim bevat met de id van de client-app:
{
"alg": "HS256",
"typ": "JWT"
}.{
"unique_name": "{USER}",
"sub": "{USER}",
"jti": "14ed7729",
"appid": "{CLIENT ID}",
"aud": [
"https://localhost:7250",
"http://localhost:7251"
],
"nbf": 1780660887,
"exp": 1788609687,
"iat": 1780660888,
"iss": "dotnet-user-jwts"
}.[Signature]
Voer de opdracht opnieuw uit met een onjuiste client-id (appid)-waarde:
dotnet user-jwts create --claim appid=aaaabbbb-0000-cccc-1111-dddd2222eeee
Stel de waarde van het tweede token apart in.
Start zowel de projecten Contoso.API en Contoso.Security.API in Visual Studio als met de opdracht dotnet watch in een opdrachtsvenster:
dotnet watch
Selecteer in de Swagger-gebruikersinterface van het Contoso.API project (https://localhost:7250/swagger/index.html) de knop Autoriseren .
Voer in het venster Beschikbare autorisaties Bearer het toegangstoken in. Selecteer de knop Autoriseren . Sluit het venster Beschikbare autorisaties .
Selecteer onder standaard de knop Ophalen voor het /WeatherForecast eindpunt. Selecteer de knop Uitproberen . Selecteer de knop Uitvoeren .
De uitvoer onder Antwoorden>Serverantwoord>Antwoordtekst toont de JSON met de weersvoorspelling die door het Contoso.API-project wordt geretourneerd.
Voer dezelfde stappen uit met het toegangstoken dat is gegenereerd met een ongeldige client-app-id. Het antwoord is 403 - Verboden.