Delen via


Autorisatie op basis van resources in ASP.NET Core

Autorisatiebenadering is afhankelijk van de resource. Alleen de auteur van een document is bijvoorbeeld gemachtigd om het document bij te werken. Daarom moet het document worden opgehaald uit het gegevensarchief voordat autorisatie-evaluatie kan plaatsvinden.

Kenmerkevaluatie vindt plaats vóór gegevensbinding en vóór de uitvoering van de pagina-handler of actie waarmee het document wordt geladen. Om deze redenen volstaat declaratieve autorisatie met een kenmerk [Authorize] niet. In plaats daarvan kunt u een aangepaste autorisatiemethode aanroepen, een stijl die bekend staat als imperatieve autorisatie.

Voorbeeldcode weergeven of downloaden (hoe te downloaden).

Een ASP.NET Core-app maken met gebruikersgegevens die worden beveiligd door autorisatie een voorbeeld-app bevat die gebruikmaakt van autorisatie op basis van resources.

Imperatieve autorisatie gebruiken

Autorisatie wordt geïmplementeerd als een IAuthorizationService-service en wordt geregistreerd in de serviceverzameling bij het opstarten van de toepassing. De dienst wordt beschikbaar gemaakt via afhankelijkheidsinjectie aan paginahandlers of acties.

public class DocumentController : Controller
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IDocumentRepository _documentRepository;

    public DocumentController(IAuthorizationService authorizationService,
                              IDocumentRepository documentRepository)
    {
        _authorizationService = authorizationService;
        _documentRepository = documentRepository;
    }

IAuthorizationService heeft twee AuthorizeAsync methodeoverlaadcodes: eentje die de resource en de beleidsnaam accepteert en de andere die de resource accepteert en een lijst met vereisten om te evalueren.

Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          string policyName);

In het volgende voorbeeld wordt de te beveiligen resource geladen in een aangepast Document-object. Er wordt een AuthorizeAsync overload aangeroepen om te bepalen of de huidige gebruiker het opgegeven document mag bewerken. Een aangepast autorisatiebeleid voor EditPolicy wordt meegenomen in de beslissing. Zie op beleid gebaseerde autorisatie voor meer informatie over het maken van autorisatiebeleid.

Notitie

In de volgende codevoorbeelden wordt ervan uitgegaan dat verificatie is uitgevoerd en de eigenschap User is ingesteld.

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, "EditPolicy");

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Een handler op basis van resources schrijven

Het schrijven van een handler voor autorisatie op basis van resources verschilt niet veel van het schrijven van een handler voor gewone vereisten. Maak een aangepaste vereisteklasse en implementeer een vereistehandlerklasse. Zie Vereistenvoor meer informatie over het maken van een vereisteklasse.

De handlerklasse specificeert zowel de vereiste als het resourcetype. Een handler die bijvoorbeeld gebruikmaakt van een SameAuthorRequirement en een Document-resource, volgt:

public class DocumentAuthorizationHandler : 
    AuthorizationHandler<SameAuthorRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   SameAuthorRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

public class SameAuthorRequirement : IAuthorizationRequirement { }

Stel in het voorgaande voorbeeld voor dat SameAuthorRequirement een speciaal geval is van een algemenere SpecificAuthorRequirement klasse. De SpecificAuthorRequirement-klasse (niet weergegeven) bevat een Name eigenschap die de naam van de auteur vertegenwoordigt. De eigenschap Name kan worden ingesteld op de huidige gebruiker.

Registreer de vereiste en verwerker in Program.cs:

builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("EditPolicy", policy =>
        policy.Requirements.Add(new SameAuthorRequirement()));
});

builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
builder.Services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
builder.Services.AddScoped<IDocumentRepository, DocumentRepository>();

Operationele vereisten

Als u beslissingen neemt op basis van de resultaten van CRUD-bewerkingen (Maken, Lezen, Bijwerken, Verwijderen), gebruikt u de OperationAuthorizationRequirement helperklasse. Met deze klasse kunt u één handler schrijven in plaats van een afzonderlijke klasse voor elk bewerkingstype. Als u deze wilt gebruiken, geeft u enkele bewerkingsnamen op:

public static class Operations
{
    public static OperationAuthorizationRequirement Create =
        new OperationAuthorizationRequirement { Name = nameof(Create) };
    public static OperationAuthorizationRequirement Read =
        new OperationAuthorizationRequirement { Name = nameof(Read) };
    public static OperationAuthorizationRequirement Update =
        new OperationAuthorizationRequirement { Name = nameof(Update) };
    public static OperationAuthorizationRequirement Delete =
        new OperationAuthorizationRequirement { Name = nameof(Delete) };
}

De handler wordt als volgt geïmplementeerd met behulp van een OperationAuthorizationRequirement vereiste en een Document resource:

public class DocumentAuthorizationCrudHandler :
    AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   OperationAuthorizationRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author &&
            requirement.Name == Operations.Read.Name)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

De voorgaande handler valideert de bewerking met behulp van de resource, de identiteit van de gebruiker en de Name eigenschap van de vereiste.

Uitdagen en verbieden met een beheerder voor operationele middelen

In deze sectie wordt uitgelegd hoe de resultaten van de uitdagingen en verbodsacties worden afgehandeld en hoe uitdagingen en verboden van elkaar verschillen.

Als u een operationele resource-handler wilt aanroepen, geeft u de bewerking op bij het aanroepen van AuthorizeAsync in de pagina-handler of actie. In het volgende voorbeeld wordt bepaald of de geverifieerde gebruiker het opgegeven document mag bekijken.

Notitie

In de volgende codevoorbeelden wordt ervan uitgegaan dat verificatie is uitgevoerd en de eigenschap User is ingesteld.

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, Operations.Read);

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Als de autorisatie is geslaagd, wordt de pagina voor het weergeven van het document geretourneerd. Als de autorisatie mislukt, maar de gebruiker is geverifieerd, informeert het retourneren van ForbidResult elke verificatie-middleware dat de autorisatie is mislukt. Er wordt een ChallengeResult geretourneerd wanneer verificatie moet worden uitgevoerd. Voor interactieve browserclients kan het handig zijn om de gebruiker om te leiden naar een aanmeldingspagina.

Autorisatiebenadering is afhankelijk van de resource. Alleen de auteur van een document is bijvoorbeeld gemachtigd om het document bij te werken. Daarom moet het document worden opgehaald uit het gegevensarchief voordat autorisatie-evaluatie kan plaatsvinden.

Kenmerkevaluatie vindt plaats vóór gegevensbinding en vóór de uitvoering van de pagina-handler of actie waarmee het document wordt geladen. Om deze redenen volstaat declaratieve autorisatie met een kenmerk [Authorize] niet. In plaats daarvan kunt u een aangepaste autorisatiemethode aanroepen, een stijl die bekend staat als imperatieve autorisatie.

Bekijk of download voorbeeldcode (hoe u kunt downloaden).

Een ASP.NET Core-app maken met gebruikersgegevens die worden beveiligd door autorisatie een voorbeeld-app bevat die gebruikmaakt van autorisatie op basis van resources.

Imperatieve autorisatie gebruiken

Autorisatie wordt geïmplementeerd als een IAuthorizationService-service en wordt geregistreerd in de serviceverzameling binnen de Startup-klasse. De service wordt beschikbaar gesteld aan pagina-afhandelaars of acties via afhankelijkheidsinjectie.

public class DocumentController : Controller
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IDocumentRepository _documentRepository;

    public DocumentController(IAuthorizationService authorizationService,
                              IDocumentRepository documentRepository)
    {
        _authorizationService = authorizationService;
        _documentRepository = documentRepository;
    }

IAuthorizationService heeft twee AuthorizeAsync method overloads: één die de resource en de beleidsnaam accepteert en een andere die de resource en een lijst met te evalueren vereisten accepteert.

Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          string policyName);

In het volgende voorbeeld wordt de te beveiligen resource geladen in een aangepast Document-object. Er wordt een AuthorizeAsync overload-functie aangeroepen om te bepalen of de huidige gebruiker het opgegeven document mag bewerken. Een aangepast autorisatiebeleid voor EditPolicy wordt meegenomen in de beslissing. Zie op beleid gebaseerde autorisatie voor meer informatie over het maken van autorisatiebeleid.

Notitie

In de volgende codevoorbeelden wordt ervan uitgegaan dat verificatie is uitgevoerd en de eigenschap User is ingesteld.

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, "EditPolicy");

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Een handler op basis van resources schrijven

Het schrijven van een handler voor autorisatie op basis van resources verschilt niet veel van het schrijven van een handler voor gewone vereisten. Maak een aangepaste vereisteklasse en implementeer een vereistehandlerklasse. Zie Vereistenvoor meer informatie over het maken van een vereisteklasse.

De handlerklasse specificeert zowel de vereiste als het resourcetype. Een handler die bijvoorbeeld gebruikmaakt van een SameAuthorRequirement en een Document-resource, volgt:

public class DocumentAuthorizationHandler : 
    AuthorizationHandler<SameAuthorRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   SameAuthorRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

public class SameAuthorRequirement : IAuthorizationRequirement { }

Stel in het voorgaande voorbeeld voor dat SameAuthorRequirement een speciaal geval is van een algemenere SpecificAuthorRequirement klasse. De SpecificAuthorRequirement-klasse (niet weergegeven) bevat een Name eigenschap die de naam van de auteur vertegenwoordigt. De eigenschap Name kan worden ingesteld op de huidige gebruiker.

Registreer de vereiste en handler in Startup.ConfigureServices:

services.AddControllersWithViews();
services.AddRazorPages();

services.AddAuthorization(options =>
{
    options.AddPolicy("EditPolicy", policy =>
        policy.Requirements.Add(new SameAuthorRequirement()));
});

services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
services.AddScoped<IDocumentRepository, DocumentRepository>();

Operationele vereisten

Als u beslissingen neemt op basis van de resultaten van CRUD-bewerkingen (Maken, Lezen, Bijwerken, Verwijderen), gebruikt u de OperationAuthorizationRequirement helperklasse. Met deze klasse kunt u één handler schrijven in plaats van een afzonderlijke klasse voor elk bewerkingstype. Als u deze wilt gebruiken, geeft u enkele bewerkingsnamen op:

public static class Operations
{
    public static OperationAuthorizationRequirement Create =
        new OperationAuthorizationRequirement { Name = nameof(Create) };
    public static OperationAuthorizationRequirement Read =
        new OperationAuthorizationRequirement { Name = nameof(Read) };
    public static OperationAuthorizationRequirement Update =
        new OperationAuthorizationRequirement { Name = nameof(Update) };
    public static OperationAuthorizationRequirement Delete =
        new OperationAuthorizationRequirement { Name = nameof(Delete) };
}

De handler wordt als volgt geïmplementeerd met behulp van een OperationAuthorizationRequirement vereiste en een Document resource:

public class DocumentAuthorizationCrudHandler :
    AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   OperationAuthorizationRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author &&
            requirement.Name == Operations.Read.Name)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

De voorgaande handler valideert de bewerking met behulp van de resource, de identiteit van de gebruiker en de Name eigenschap van de vereiste.

Uitdaging en verbieden met een handler voor operationele resources

In deze sectie ziet u hoe de resultaten van de acties uitdaging en verbod worden verwerkt en hoe zij verschillen.

Als u een operationele resource-handler wilt aanroepen, geeft u de bewerking op bij het aanroepen van AuthorizeAsync in de pagina-handler of actie. In het volgende voorbeeld wordt bepaald of de geverifieerde gebruiker het opgegeven document mag bekijken.

Notitie

In de volgende codevoorbeelden wordt ervan uitgegaan dat verificatie is uitgevoerd en de eigenschap User is ingesteld.

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, Operations.Read);

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Als de autorisatie is geslaagd, wordt de pagina voor het weergeven van het document geretourneerd. Als de autorisatie mislukt, maar de gebruiker is geauthentiseerd, informeert ForbidResult de authenticatiemiddleware dat de autorisatie is mislukt. Er wordt een ChallengeResult geretourneerd wanneer verificatie moet worden uitgevoerd. Voor interactieve browserclients kan het handig zijn om de gebruiker om te leiden naar een aanmeldingspagina.

Autorisatiebenadering is afhankelijk van de resource. Alleen de auteur van een document is bijvoorbeeld gemachtigd om het document bij te werken. Daarom moet het document worden opgehaald uit het gegevensarchief voordat autorisatie-evaluatie kan plaatsvinden.

Kenmerkevaluatie vindt plaats vóór gegevensbinding en vóór de uitvoering van de pagina-handler of actie waarmee het document wordt geladen. Om deze redenen volstaat declaratieve autorisatie met een kenmerk [Authorize] niet. In plaats daarvan kunt u een aangepaste autorisatiemethode aanroepen, een stijl die bekend staat als imperatieve autorisatie.

Bekijk of download de voorbeeldcode (hoe te downloaden).

Een ASP.NET Core-app maken met gebruikersgegevens die worden beveiligd door autorisatie een voorbeeld-app bevat die gebruikmaakt van autorisatie op basis van resources.

Imperatieve autorisatie gebruiken

Autorisatie wordt geïmplementeerd als een IAuthorizationService-service en wordt geregistreerd in de serviceverzameling binnen de Startup-klasse. De dienst wordt via afhankelijkheidsinjectie beschikbaar gesteld aan pagina-handlers of acties.

public class DocumentController : Controller
{
    private readonly IAuthorizationService _authorizationService;
    private readonly IDocumentRepository _documentRepository;

    public DocumentController(IAuthorizationService authorizationService,
                              IDocumentRepository documentRepository)
    {
        _authorizationService = authorizationService;
        _documentRepository = documentRepository;
    }

IAuthorizationService heeft twee AuthorizeAsync method overloads: één die de resource en de beleidsnaam accepteert en de andere die de resource en een lijst met vereisten accepteert om te evalueren.

Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user,
                          object resource,
                          string policyName);

In het volgende voorbeeld wordt de te beveiligen resource geladen in een aangepast Document-object. Er wordt een AuthorizeAsync overload aangeroepen om te bepalen of de huidige gebruiker het opgegeven document mag bewerken. Een aangepast autorisatiebeleid voor EditPolicy wordt meegenomen in de beslissing. Zie op beleid gebaseerde autorisatie voor meer informatie over het maken van autorisatiebeleid.

Notitie

In de volgende codevoorbeelden wordt ervan uitgegaan dat verificatie is uitgevoerd en de eigenschap User is ingesteld.

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, "EditPolicy");

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Een handler op basis van resources schrijven

Het schrijven van een handler voor autorisatie op basis van resources verschilt niet veel van het schrijven van een handler voor gewone vereisten. Maak een aangepaste vereisteklasse en implementeer een vereistehandlerklasse. Zie Vereistenvoor meer informatie over het maken van een vereisteklasse.

De handlerklasse specificeert zowel de vereiste als het resourcetype. Een handler die bijvoorbeeld gebruikmaakt van een SameAuthorRequirement en een Document-resource, volgt:

public class DocumentAuthorizationHandler : 
    AuthorizationHandler<SameAuthorRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   SameAuthorRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

public class SameAuthorRequirement : IAuthorizationRequirement { }

Stel in het voorgaande voorbeeld voor dat SameAuthorRequirement een speciaal geval is van een algemenere SpecificAuthorRequirement klasse. De SpecificAuthorRequirement-klasse (niet weergegeven) bevat een Name eigenschap die de naam van de auteur vertegenwoordigt. De eigenschap Name kan worden ingesteld op de huidige gebruiker.

Registreer de vereiste en handler in Startup.ConfigureServices:

services.AddMvc();

services.AddAuthorization(options =>
{
    options.AddPolicy("EditPolicy", policy =>
        policy.Requirements.Add(new SameAuthorRequirement()));
});

services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationCrudHandler>();
services.AddScoped<IDocumentRepository, DocumentRepository>();

Operationele vereisten

Als u beslissingen neemt op basis van de resultaten van CRUD-bewerkingen (Maken, Lezen, Bijwerken, Verwijderen), gebruikt u de OperationAuthorizationRequirement helperklasse. Met deze klasse kunt u één handler schrijven in plaats van een afzonderlijke klasse voor elk bewerkingstype. Als u deze wilt gebruiken, geeft u enkele bewerkingsnamen op:

public static class Operations
{
    public static OperationAuthorizationRequirement Create =
        new OperationAuthorizationRequirement { Name = nameof(Create) };
    public static OperationAuthorizationRequirement Read =
        new OperationAuthorizationRequirement { Name = nameof(Read) };
    public static OperationAuthorizationRequirement Update =
        new OperationAuthorizationRequirement { Name = nameof(Update) };
    public static OperationAuthorizationRequirement Delete =
        new OperationAuthorizationRequirement { Name = nameof(Delete) };
}

De handler wordt als volgt geïmplementeerd met behulp van een OperationAuthorizationRequirement vereiste en een Document resource:

public class DocumentAuthorizationCrudHandler :
    AuthorizationHandler<OperationAuthorizationRequirement, Document>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   OperationAuthorizationRequirement requirement,
                                                   Document resource)
    {
        if (context.User.Identity?.Name == resource.Author &&
            requirement.Name == Operations.Read.Name)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

De voorgaande handler valideert de bewerking met behulp van de resource, de identiteit van de gebruiker en de Name eigenschap van de vereiste.

Uitdagen en verbieden met een handler voor operationele bronnen

In deze sectie ziet u hoe de resultaten van aanvechten en verbieden worden verwerkt en hoe deze twee acties verschillen.

Als u een operationele resource-handler wilt aanroepen, geeft u de bewerking op bij het aanroepen van AuthorizeAsync in de pagina-handler of actie. In het volgende voorbeeld wordt bepaald of de geverifieerde gebruiker het opgegeven document mag bekijken.

Notitie

In de volgende codevoorbeelden wordt ervan uitgegaan dat verificatie is uitgevoerd en de eigenschap User is ingesteld.

public async Task<IActionResult> OnGetAsync(Guid documentId)
{
    Document = _documentRepository.Find(documentId);

    if (Document == null)
    {
        return new NotFoundResult();
    }

    var authorizationResult = await _authorizationService
            .AuthorizeAsync(User, Document, Operations.Read);

    if (authorizationResult.Succeeded)
    {
        return Page();
    }
    else if (User.Identity.IsAuthenticated)
    {
        return new ForbidResult();
    }
    else
    {
        return new ChallengeResult();
    }
}

Als de autorisatie is geslaagd, wordt de pagina voor het weergeven van het document geretourneerd. Als de autorisatie mislukt, maar de gebruiker is geauthenticeerd, informeert het retourneren van ForbidResult de authenticatiemiddleware dat de autorisatie is mislukt. Er wordt een ChallengeResult geretourneerd wanneer verificatie moet worden uitgevoerd. Voor interactieve browserclients kan het handig zijn om de gebruiker om te leiden naar een aanmeldingspagina.