Principbaserad auktorisering i ASP.NET Core

En ASP.NET Core auktoriseringsprincip är en namngiven uppsättning med ett eller flera auktoriseringskrav som ramverket utvärderar för att avgöra om en användare får åtkomst till en resurs.

Den här artikeln förklarar:

  • Så skapar du krav.
  • Registrera och tillämpa principer.
  • Auktoriseringshanterare för utvärdering av enskilda och flera krav.
  • Hur flera krav i en enda princip utvärderas.

I praktiken tillämpas en princip med [Authorize(Policy = "...")] (Razor komponenter, sidor och kontrollanter) eller RequireAuthorization(...) (slutpunkter) och ramverket använder hanterare för att utvärdera kraven bakom en princip. IAuthorizationPolicyProvider(Anpassade auktoriseringsprincipprovidrar i ASP.NET Core dokumentation) genererar principer dynamiskt i stället för att registrera dem vid appstart.

Rollbaserad auktorisering och anspråksbaserad auktorisering använder ett krav, en kravhanterare och en förkonfigurerad auktoriseringsprincip. Dessa byggstenar stöder uttrycket för auktoriseringsutvärderingar i kod.

Den här artikeln använder Razor komponentexempel och fokuserar på Blazor auktoriseringsscenarier för ASP.NET Core 3.1 eller senare. För vägledning om Razor Pages och MVC som gäller för alla versioner av ASP.NET Core, se följande resurser efter att du har läst den här artikeln:

Några exempel i den här artikeln (ASP.NET Core 8.0 eller senare) använder primära konstruktorer, tillgängliga i C# 12 (.NET 8) eller senare. Mer information finns i Deklarera primära konstruktorer för klasser och structs (självstudiekurs om C#-dokumentation) och Primära konstruktorer (C#-guide).

Krav och policyregistrering

En auktoriseringsprincip består av ett eller flera krav som används av en princip för att utvärdera auktorisering för det aktuella användarens huvudnamn. Ett krav implementerar IAuthorizationRequirement, som är ett tomt markörgränssnitt.

När ett krav inte innehåller data eller har egenskaper (parametrar) fungerar det som en tom markör för att utlösa en associerad auktoriseringshanterare (IAuthorizationHandler) för bearbetning av auktorisering (beskrivs i detalj senare i den här artikeln). Eftersom hanteraren i det här fallet helt förlitar sig på HTTP-kontexten, användaranspråk eller serverdelsdata för att fatta ett beslut om att användaren uppfyller kravet, kräver inte själva kravklassen interna data eller parametrar. Kravet instruerar endast det ramverk som regeln ska utvärdera.

Tänk till exempel på följande minimiålderskrav (MinimumAgeRequirement), som endast har implementerats som en markörklass:

public class MinimumAgeRequirement : IAuthorizationRequirement { }

Föregående krav används för att skapa en princip som bekräftar att användaren är över en viss ålder som hanteraren kontrollerar. En AuthorizationHandler<MinimumAgeRequirement> kontrollerar AuthorizationHandlerContext.User. Om användaren har en födelsedatumsuppgift som anger att användaren är äldre än en viss ålder, uppfylls kravet. Kravobjektet kräver inga egenskaper (parametrar) i det här fallet. Nästa exempel visar den fullständiga implementeringen av ett minimikrav som har en parameter för att ange minimiålder.

Tänk på följande MinimumAgeRequirement krav, som beskriver en enskild parameter, en minimiålder, för att utvärdera för användarauktorisering:

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;
    }
}

En policy registreras som en del av auktoriseringstjänstens konfiguration i appens Program-fil genom att anropa AuthorizationBuilder.AddPolicy. I följande exempel skapas en AtLeast21 princip med ett enda krav på en minimiålder och anger minimiåldern till 21 år.

builder.Services.AddAuthorizationBuilder()
    .AddPolicy("AtLeast21", policy => 
        policy.Requirements.Add(new MinimumAgeRequirement(21)));

En policy registreras som en del av auktoriseringstjänstens konfiguration i appens Program-fil genom att anropa AuthorizationBuilder.AddPolicy. I följande exempel skapas en AtLeast21 princip med ett enda krav på en minimiålder och anger minimiåldern till 21 år:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AtLeast21", policy =>
        policy.Requirements.Add(new MinimumAgeRequirement(21)));
});

En policy registreras som en del av konfigurationen för auktoriseringstjänsten i Startup.ConfigureServices (Startup.cs) genom att anropa AuthorizationBuilder.AddPolicy. I följande exempel skapas en AtLeast21 princip med ett enda krav på en minimiålder och anger minimiåldern till 21 år:

services.AddAuthorization(options =>
{
    options.AddPolicy("AtLeast21", policy =>
        policy.Requirements.Add(new MinimumAgeRequirement(21)));
});

Om en auktoriseringsprincip innehåller flera auktoriseringskrav måste alla krav uppfyllas för att principutvärderingen ska lyckas. Med andra ord behandlas flera auktoriseringskrav som läggs till i en enda auktoriseringsprincip på AND-basis .

Tillämpa principer på Razor komponenter

Tillämpa principer på Razor komponenter med hjälp av [Authorize] attributet med principnamnet:

@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "CustomerServiceMember")]

Om flera principer tillämpas måste alla principer passera innan åtkomst beviljas:

@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "CustomerServiceMember")]
@attribute [Authorize(Policy = "HumanResourcesMember")]

Tillämpa principer på slutpunkter

Tillämpa principer på slutpunkter med hjälp av RequireAuthorization med principnamnet. Till exempel:

app.MapGet("/helloworld", () => "Hello World!")
    .RequireAuthorization("AtLeast21");

Tillämpa principer i MVC- och Razor Pages-appar

Vägledning om hur du tillämpar principer i Razor Pages- och MVC-appar finns i följande resurser:

Auktoriseringstjänstgränssnitt (IAuthorizationService)

IAuthorizationService ansvarar främst för att avgöra om auktorisering lyckas när en överlagrad version av IAuthorizationService.AuthorizeAsync anropas:

  • AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements): Kontrollerar om en användare uppfyller en specifik uppsättning auktoriseringskrav för en angiven resurs.
  • AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName): Kontrollerar om en användare uppfyller en specifik auktoriseringsprincip för en angiven resurs.

Om en resurs inte krävs för principutvärdering skickas null för resursen.

Ovanstående metoder returnerar en AuthorizationResult omsluten i en Task.

Varje IAuthorizationHandler ansvarar för att kontrollera om kraven uppfylls genom IAuthorizationHandler.HandleAsync. Klassen AuthorizationHandlerContext innehåller den auktoriseringsinformation som används av implementeringen IAuthorizationHandler . IAuthorizationRequirement är ett markörgränssnitt utan metoder som fungerar som mekanism för att spåra om auktoriseringen lyckas. När AuthorizationHandlerContext.Succeed anropas med IAuthorizationRequirementuppfylls principen:

context.Succeed(requirement);

Auktoriseringshanterare

En auktoriseringshanterare ansvarar för utvärderingen av ett kravs egenskaper. Auktoriseringshanteraren utvärderar kraven mot en angivet AuthorizationHandlerContext för att avgöra om access tillåts.

Ett krav kan ha flera hanterare. En hanterare kan ärva AuthorizationHandler<TRequirement>, där TRequirement är kravet att hantera. En hanterare kan också implementera IAuthorizationHandler direkt för att hantera mer än en typ av krav.

Använd en hanterare för ett krav

I följande exempel visas en en-till-en-relation där en minimiåldershanterare hanterar ett enda krav:

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;
    }
}

Föregående kod avgör om det aktuella användarens huvudnamn har ett födelsedatum. Auktorisering kan inte utföras när anspråket saknas, i så fall returneras en slutförd uppgift. När ett anspråk finns beräknas användarens ålder. Om användaren uppfyller den lägsta ålder som definieras av kravet anses auktoriseringen vara lyckad. När auktoriseringen lyckas anropas context.Succeed med det uppfyllda kravet som enda parameter.

Använda en hanterare för flera krav

I följande exempel visas en en-till-många-relation där en behörighetshanterare kan hantera tre olika typer av krav:

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;
    }
}

Föregående kod passerar PendingRequirements– en egenskap som innehåller krav som inte har markerats som lyckade. För ett ReadPermission krav måste användaren antingen vara ägare eller sponsor för att få åtkomst till den begärda resursen. För ett krav på EditPermission eller DeletePermission måste de vara ägare för att få åtkomst till den begärda resursen.

Hanterarregistrering

Registrera hanterare i tjänstesamlingen under konfigurationen. I följande exempel registreras en minimiåldershanterare (MinimumAgeHandler) som en singleton-tjänst, men en hanterare kan registreras med någon av de inbyggda tjänstlivslängderna:

builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();

Det är möjligt att paketera både ett krav och en hanterare i en enda klass som implementerar både IAuthorizationRequirement och IAuthorizationHandler. Den här kombinationskopplingen skapar en nära koppling mellan hanteraren och kraven och rekommenderas endast för enkla krav och hanterare. Att skapa en klass som implementerar båda gränssnitten tar bort behovet av att registrera hanteraren i tjänstcontainern på grund av den inbyggda PassThroughAuthorizationHandler som gör att kraven kan hantera sig själva.

Se implementeringen av klassen ASP.NET Core AssertionRequirement för ett exempel där AssertionRequirement är både ett krav och hanteraren i en helt fristående klass. API:et i AssertionRequirement-ramverket gör att du kan validera åtkomst med hjälp av inbäddade lambdauttryck i stället för att skriva separata krav- och hanterarklasser med standardkod.

Note

Dokumentationslänkar till .NET-referenskällan läser vanligtvis in lagringsplatsens standardgren, vilket representerar den aktuella utvecklingen för nästa version av .NET. Om du vill välja en tagg för en specifik version använder du listrutan Välj bland grenar eller taggar. Mer information finns i Så här väljer du en versionstagg för ASP.NET Core-källkod (dotnet/AspNetCore.Docs #26205).

Vad ska en hanterare returnera?

Metoden Handle i hanteringsexemplet returnerar inget värde. Hur anges statusen för antingen lyckad eller misslyckad?

  • En hanterare anger att det lyckades genom att anropa context.Succeedoch skicka det verifierade kravet (IAuthorizationRequirement).

  • En hanterare krävs inte för att hantera fel i allmänhet, eftersom andra hanterare för samma krav kan lyckas.

  • Om du vill garantera misslyckande, även om andra hanterare av krav lyckas, anropar du context.Fail.

Om en hanterare anropar context.Succeed eller context.Failanropas fortfarande alla andra hanterare. Detta gör att kraven kan ge biverkningar, till exempel loggning, som sker även om en annan hanterare validerar eller misslyckas på ett krav. När värdet är inställt på falsekortsluter egenskapen InvokeHandlersAfterFailure körningen av hanterare när context.Fail anropas. InvokeHandlersAfterFailure återgår till true, i vilket fall alla hanterare anropas.

Note

Auktoriseringshanterare anropas även om autentiseringen misslyckas. Hanterare kan också köras i valfri ordning, så förlita dig inte på i vilken ordning hanterare anropas.

Varför skulle jag vilja ha flera hanterare för ett krav?

I de fall där du vill att utvärderingen ska vara på OR-basis implementerar du flera hanterare för ett enda krav. Anta till exempel att Contoso Corporation har dörrar som endast öppnas med nyckelkort. Om du lämnar ditt nyckelkort hemma skriver receptionisten ut ett tillfälligt klistermärke och öppnar dörren åt dig. I det här scenariot har appen ett enda krav men flera hanterare, där var och en undersöker ett enda krav.

I följande exempelimplementeringar:

  • BuildingEntryRequirement är kravet för tillträde till byggnaden.
  • BadgeEntryHandler (personen har ett märke) och TemporaryStickerHandler (personen har ett tillfälligt klistermärke) är separata hanterare, var och en undersöker ett enda krav.

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;
    }
}

Kontrollera att båda hanterarna är registrerade. Om någon av hanterarna lyckas när en princip utvärderar BuildingEntryRequirement, lyckas utvärderingen av principen.

Använd en Func för att uppfylla en policy

Det finns situationer där en policy enkelt kan uttryckas i kod med en Func<AuthorizationHandlerContext, bool> delegat när du konfigurerar en policy med policybyggaren RequireAssertion. Till exempel kan föregående BadgeEntryHandler skrivas om på följande sätt:

    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")));
});

Kräv global användarautentisering

Information om hur du kräver autentisering för alla appanvändare finns i Skapa en ASP.NET Core app med användardata som skyddas av auktorisering.

Auktorisering via ett externt tjänstexempel

Auktoriseringen via ett externt tjänstexempel (dotnet/AspNetCore.Docs.Samples GitHub lagringsplats) visar hur du implementerar ytterligare auktoriseringskrav med en extern auktoriseringstjänst. Lösningens Contoso.API projekt skyddas med Microsoft Entra ID. En ytterligare auktoriseringskontroll från Contoso.Security.API project returnerar en nyttolast som beskriver om klientappen Contoso.API kan anropa api:et GetWeather.

Konfigurera exemplet

Följande demonstration förlitar sig på att använda NSwag (Swagger/OpenAPI) eller cURL i ett kommandogränssnitt.

I Contoso.Security.API-projektet ställer du in platshållaren AllowedClients ({CLIENT ID}) på ett valfritt GUID-testvärde (till exempel 00001111-aaaa-2222-bbbb-3333cccc4444):

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "AllowedClients": [
    "{CLIENT ID (FOR THE CLIENT CALLING CONTOSO.API)}"
  ]
}

I ett kommandogränssnitt som öppnats för Contoso.API projektet använder du dotnet user-jwts för att generera en åtkomsttoken med ett appid anspråk för klientappens ID, som skapades i föregående steg (till exempel 00001111-aaaa-2222-bbbb-3333cccc4444).

dotnet user-jwts create --claim appid={GUID}

Exempel:

dotnet user-jwts create --claim appid=00001111-aaaa-2222-bbbb-3333cccc4444

Utdata genererar en token efter "Token:" i kommandogränssnittet:

New JWT saved with ID '{JWT ID}'.
Name: {USER}
Custom Claims: [appid=00001111-aaaa-2222-bbbb-3333cccc4444]

Token: {TOKEN}

Spara värdet för token (där {TOKEN} platshållaren visas i föregående utdata) för senare användning.

Du kan avkoda token i en onlinedekodare JWT , till exempel jwt.ms för att se dess innehåll, vilket avslöjar att den innehåller ett appid anspråk med klientappens ID:

{
  "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]

Kör kommandot igen med ett felaktigt klient-ID (appid) värde:

dotnet user-jwts create --claim appid=aaaabbbb-0000-cccc-1111-dddd2222eeee

Sätt åt sidan värdet för den andra token.

Starta både Contoso.API projekten och Contoso.Security.API i Visual Studio eller med dotnet watch kommandot i ett kommandogränssnitt:

dotnet watch

I swagger-användargränssnittet för Contoso.API projektet (https://localhost:7250/swagger/index.html) väljer du knappen Auktorisera .

I fönstret Tillgängliga auktoriseringar: Bearer anger du åtkomsttoken. Välj knappen Auktorisera. Stäng fönstret Tillgängliga auktoriseringar .

Under standard väljer du knappen Hämta för /WeatherForecast slutpunkten. Välj knappen Prova . Välj knappen Kör .

Utdata under Svar>Serversvar>Svarstext visar den väderprognos-JSON som returneras av projektet Contoso.API.

Utför samma steg med åtkomsttoken som genererades med ett ogiltigt klientapp-ID. Svaret är 403 – Förbjudet.

Ytterligare resurser