Dela via


Resursbaserad auktorisering i ASP.NET Core

Auktoriseringsmetoden beror på resursen. Till exempel är det bara författaren till ett dokument som har behörighet att uppdatera dokumentet. Därför måste dokumentet hämtas från datalagret innan auktoriseringsutvärderingen kan ske.

Attribututvärderingen sker före databindningen och före körningen av sidhanteraren eller åtgärden som läser in dokumentet. Därför räcker det inte med deklarativ auktorisering med ett [Authorize] attribut. I stället kan du anropa en anpassad auktoriseringsmetod – ett format som kallas imperativ auktorisering.

Visa eller ladda ned exempelkod (hur du laddar ned).

Skapa en ASP.NET Core-app med användardata som skyddas av auktorisering innehåller en exempelapp som använder resursbaserad auktorisering.

Använda imperativ auktorisering

Auktorisering implementeras som en IAuthorizationService tjänst och registreras i tjänstsamlingen vid programstart. Tjänsten görs tillgänglig via beroendeinmatning till sidhanterare eller åtgärder.

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

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

IAuthorizationService har två AuthorizeAsync metodöverlagringar: den ena accepterar resursen och policy-namnet, och den andra accepterar resursen och en lista med krav för utvärdering.

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

I följande exempel läses den resurs som ska skyddas in i ett anpassat Document objekt. En AuthorizeAsync överlagring anropas för att avgöra om den aktuella användaren får redigera det angivna dokumentet. En anpassad "EditPolicy"-auktoriseringsprincip räknas in i beslutet. Mer information om hur du skapar auktoriseringsprinciper finns i Anpassad principbaserad auktorisering .

Note

Följande kodexempel förutsätter att autentiseringen har körts och angett egenskapen User .

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

Skriva en resursbaserad hanterare

Att skriva en hanterare för resursbaserad auktorisering skiljer sig inte mycket från att skriva en vanlig kravhanterare. Skapa en anpassad kravklass och implementera en kravhanterarklass. Mer information om hur du skapar en kravklass finns i Krav.

Hanteringsklassen anger både krav och resurstyp. Till exempel följer en hanterare som använder en SameAuthorRequirement och en Document resurs:

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

I föregående exempel kan du tänka dig att det SameAuthorRequirement är ett specialfall för en mer generisk SpecificAuthorRequirement klass. Klassen SpecificAuthorRequirement (visas inte) innehåller en Name egenskap som representerar författarens namn. Egenskapen Name kan anges till den aktuella användaren.

Registrera krav och hanterare i 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>();

Driftkrav

Om du fattar beslut baserat på resultatet av CRUD-åtgärder (Skapa, Läsa, Uppdatera, Ta bort) använder du hjälpklassen OperationAuthorizationRequirement . Med den här klassen kan du skriva en enskild hanterare i stället för en enskild klass för varje åtgärdstyp. Om du vill använda den anger du några åtgärdsnamn:

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

Hanteraren implementeras på följande sätt med hjälp av ett OperationAuthorizationRequirement krav och en Document resurs:

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

Föregående hanterare verifierar åtgärden med hjälp av resursen, användarens identitet och kravets Name egenskap.

Utmana och förbjud en operativ resurs hanterare

Det här avsnittet visar hur utmaning och förbjudande åtgärdsresultat bearbetas och hur utmanings- och förbjudande åtgärder skiljer sig åt.

Om du vill anropa en driftresurshanterare anger du åtgärden när du anropar AuthorizeAsync i sidhanteraren eller åtgärden. I följande exempel avgörs om den autentiserade användaren har behörighet att visa det angivna dokumentet.

Note

Följande kodexempel förutsätter att autentiseringen har körts och angett egenskapen User .

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

Om auktoriseringen lyckas returneras sidan för att visa dokumentet. Om auktoriseringen misslyckas men användaren autentiseras, att returnera ForbidResult informerar alla autentiserings-mellanprogram om att auktoriseringen misslyckades. A ChallengeResult returneras när autentiseringen måste utföras. För interaktiva webbläsarklienter kan det vara lämpligt att omdirigera användaren till en inloggningssida.

Auktoriseringsmetoden beror på resursen. Till exempel är det bara författaren till ett dokument som har behörighet att uppdatera dokumentet. Därför måste dokumentet hämtas från datalagret innan auktoriseringsutvärderingen kan ske.

Attribututvärderingen sker före databindningen och före körningen av sidhanteraren eller åtgärden som läser in dokumentet. Därför räcker det inte med deklarativ auktorisering med ett [Authorize] attribut. I stället kan du anropa en anpassad auktoriseringsmetod – ett format som kallas imperativ auktorisering.

Visa eller ladda ned exempelkod (hur du laddar ned).

Skapa en ASP.NET Core-app med användardata som skyddas av auktorisering innehåller en exempelapp som använder resursbaserad auktorisering.

Använda imperativ auktorisering

Auktorisering implementeras som en IAuthorizationService tjänst och registreras i tjänstsamlingen Startup i klassen. Tjänsten görs tillgänglig via beroendeinmatning till sidhanterare eller åtgärder.

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

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

IAuthorizationService har två AuthorizeAsync metodöverlagringar: den ena accepterar resursen och policy-namnet, och den andra accepterar resursen och en lista med krav för utvärdering.

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

I följande exempel läses den resurs som ska skyddas in i ett anpassat Document objekt. En AuthorizeAsync överlagring anropas för att avgöra om den aktuella användaren får redigera det angivna dokumentet. En anpassad "EditPolicy"-auktoriseringsprincip räknas in i beslutet. Mer information om hur du skapar auktoriseringsprinciper finns i Anpassad principbaserad auktorisering .

Note

Följande kodexempel förutsätter att autentiseringen har körts och angett egenskapen User .

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

Skriva en resursbaserad hanterare

Att skriva en hanterare för resursbaserad auktorisering skiljer sig inte mycket från att skriva en vanlig kravhanterare. Skapa en anpassad kravklass och implementera en kravhanterarklass. Mer information om hur du skapar en kravklass finns i Krav.

Hanteringsklassen anger både krav och resurstyp. Till exempel följer en hanterare som använder en SameAuthorRequirement och en Document resurs:

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

I föregående exempel kan du tänka dig att det SameAuthorRequirement är ett specialfall för en mer generisk SpecificAuthorRequirement klass. Klassen SpecificAuthorRequirement (visas inte) innehåller en Name egenskap som representerar författarens namn. Egenskapen Name kan anges till den aktuella användaren.

Registrera krav och hanterare i 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>();

Driftkrav

Om du fattar beslut baserat på resultatet av CRUD-åtgärder (Skapa, Läsa, Uppdatera, Ta bort) använder du hjälpklassen OperationAuthorizationRequirement . Med den här klassen kan du skriva en enskild hanterare i stället för en enskild klass för varje åtgärdstyp. Om du vill använda den anger du några åtgärdsnamn:

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

Hanteraren implementeras på följande sätt med hjälp av ett OperationAuthorizationRequirement krav och en Document resurs:

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

Föregående hanterare verifierar åtgärden med hjälp av resursen, användarens identitet och kravets Name egenskap.

Utmana och förbjud en operativ resurs hanterare

Det här avsnittet visar hur utmaning och förbjudande åtgärdsresultat bearbetas och hur utmanings- och förbjudande åtgärder skiljer sig åt.

Om du vill anropa en driftresurshanterare anger du åtgärden när du anropar AuthorizeAsync i sidhanteraren eller åtgärden. I följande exempel avgörs om den autentiserade användaren har behörighet att visa det angivna dokumentet.

Note

Följande kodexempel förutsätter att autentiseringen har körts och angett egenskapen User .

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

Om auktoriseringen lyckas returneras sidan för att visa dokumentet. Om auktoriseringen misslyckas men användaren autentiseras, att returnera ForbidResult informerar alla autentiserings-mellanprogram om att auktoriseringen misslyckades. A ChallengeResult returneras när autentiseringen måste utföras. För interaktiva webbläsarklienter kan det vara lämpligt att omdirigera användaren till en inloggningssida.

Auktoriseringsmetoden beror på resursen. Till exempel är det bara författaren till ett dokument som har behörighet att uppdatera dokumentet. Därför måste dokumentet hämtas från datalagret innan auktoriseringsutvärderingen kan ske.

Attribututvärderingen sker före databindningen och före körningen av sidhanteraren eller åtgärden som läser in dokumentet. Därför räcker det inte med deklarativ auktorisering med ett [Authorize] attribut. I stället kan du anropa en anpassad auktoriseringsmetod – ett format som kallas imperativ auktorisering.

Visa eller ladda ned exempelkod (hur du laddar ned).

Skapa en ASP.NET Core-app med användardata som skyddas av auktorisering innehåller en exempelapp som använder resursbaserad auktorisering.

Använda imperativ auktorisering

Auktorisering implementeras som en IAuthorizationService tjänst och registreras i tjänstsamlingen Startup i klassen. Tjänsten görs tillgänglig via beroendeinmatning till sidhanterare eller åtgärder.

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

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

IAuthorizationService har två AuthorizeAsync metodöverlagringar: den ena accepterar resursen och policy-namnet, och den andra accepterar resursen och en lista med krav för utvärdering.

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

I följande exempel läses den resurs som ska skyddas in i ett anpassat Document objekt. En AuthorizeAsync överlagring anropas för att avgöra om den aktuella användaren får redigera det angivna dokumentet. En anpassad "EditPolicy"-auktoriseringsprincip räknas in i beslutet. Mer information om hur du skapar auktoriseringsprinciper finns i Anpassad principbaserad auktorisering .

Note

Följande kodexempel förutsätter att autentiseringen har körts och angett egenskapen User .

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

Skriva en resursbaserad hanterare

Att skriva en hanterare för resursbaserad auktorisering skiljer sig inte mycket från att skriva en vanlig kravhanterare. Skapa en anpassad kravklass och implementera en kravhanterarklass. Mer information om hur du skapar en kravklass finns i Krav.

Hanteringsklassen anger både krav och resurstyp. Till exempel följer en hanterare som använder en SameAuthorRequirement och en Document resurs:

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

I föregående exempel kan du tänka dig att det SameAuthorRequirement är ett specialfall för en mer generisk SpecificAuthorRequirement klass. Klassen SpecificAuthorRequirement (visas inte) innehåller en Name egenskap som representerar författarens namn. Egenskapen Name kan anges till den aktuella användaren.

Registrera krav och hanterare i 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>();

Driftkrav

Om du fattar beslut baserat på resultatet av CRUD-åtgärder (Skapa, Läsa, Uppdatera, Ta bort) använder du hjälpklassen OperationAuthorizationRequirement . Med den här klassen kan du skriva en enskild hanterare i stället för en enskild klass för varje åtgärdstyp. Om du vill använda den anger du några åtgärdsnamn:

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

Hanteraren implementeras på följande sätt med hjälp av ett OperationAuthorizationRequirement krav och en Document resurs:

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

Föregående hanterare verifierar åtgärden med hjälp av resursen, användarens identitet och kravets Name egenskap.

Utmana och förbjud en operativ resurs hanterare

Det här avsnittet visar hur utmaning och förbjudande åtgärdsresultat bearbetas och hur utmanings- och förbjudande åtgärder skiljer sig åt.

Om du vill anropa en driftresurshanterare anger du åtgärden när du anropar AuthorizeAsync i sidhanteraren eller åtgärden. I följande exempel avgörs om den autentiserade användaren har behörighet att visa det angivna dokumentet.

Note

Följande kodexempel förutsätter att autentiseringen har körts och angett egenskapen User .

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

Om auktoriseringen lyckas returneras sidan för att visa dokumentet. Om auktoriseringen misslyckas men användaren autentiseras, att returnera ForbidResult informerar alla autentiserings-mellanprogram om att auktoriseringen misslyckades. A ChallengeResult returneras när autentiseringen måste utföras. För interaktiva webbläsarklienter kan det vara lämpligt att omdirigera användaren till en inloggningssida.