Sdílet prostřednictvím


Autorizace založená na prostředcích v ASP.NET Core

Přístup k autorizaci závisí na prostředku. Například k aktualizaci dokumentu má oprávnění pouze autor dokumentu. V důsledku toho musí být dokument načten z úložiště dat před vyhodnocením autorizace.

Vyhodnocení atributu probíhá před datovou vazbou a před spuštěním obslužné rutiny stránky nebo akce, která dokument načte. Z těchto důvodů nestačí deklarativní autorizace s atributem [Authorize] . Místo toho můžete vyvolat vlastní metodu autorizace – styl označovaný jako imperativní autorizace.

Zobrazení nebo stažení vzorového kódu (postup stažení)

Vytvoření aplikace ASP.NET Core s uživatelskými daty chráněnými autorizací obsahuje ukázkovou aplikaci, která používá autorizaci založenou na prostředcích.

Použití imperativní autorizace

Autorizace se implementuje jako IAuthorizationService služba a je zaregistrovaná v kolekci služeb při spuštění aplikace. Služba je dostupná prostřednictvím injektáže závislostí pro obslužné rutiny nebo akce stránky.

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

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

IAuthorizationService má dvě AuthorizeAsync přetížení metod: jeden přijímá prostředek a název zásady a druhý přijímá prostředek a seznam požadavků k vyhodnocení.

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

V následujícím příkladu je prostředek, který se má zabezpečit, načten do vlastního Document objektu. Vyvolá AuthorizeAsync se přetížení, které určuje, jestli má aktuální uživatel povoleno upravovat zadaný dokument. Do rozhodnutí se zamítá vlastní zásady autorizace EditPolicy. Další informace o vytváření zásad autorizace najdete v tématu Vlastní autorizace na základě zásad.

Poznámka:

Následující ukázky kódu předpokládají, že se spustilo ověřování a nastavila User vlastnost.

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

Zápis obslužné rutiny založené na prostředcích

Zápis obslužné rutiny pro autorizaci na základě prostředků se moc neliší od zápisu obslužné rutiny prostých požadavků. Vytvořte vlastní třídu požadavků a implementujte třídu obslužné rutiny požadavku. Další informace o vytvoření třídy požadavků naleznete v tématu Požadavky.

Třída obslužné rutiny určuje požadavek i typ prostředku. Například obslužná rutina využívající SameAuthorRequirement prostředek a Document prostředek:

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

V předchozím příkladu si představte, že SameAuthorRequirement jde o speciální případ obecnější SpecificAuthorRequirement třídy. Třída SpecificAuthorRequirement (není zobrazena) obsahuje Name vlastnost představující jméno autora. Name Vlastnost může být nastavena na aktuálního uživatele.

Zaregistrujte požadavek a obslužnou rutinu v 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>();

Provozní požadavky

Pokud provádíte rozhodnutí na základě výsledků operací CRUD (vytvoření, čtení, aktualizace, odstranění), použijte pomocnou OperationAuthorizationRequirement třídu. Tato třída umožňuje psát jednu obslužnou rutinu místo jednotlivé třídy pro každý typ operace. Pokud ho chcete použít, zadejte několik názvů operací:

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

Obslužná rutina se implementuje následujícím způsobem pomocí OperationAuthorizationRequirement požadavku a Document prostředku:

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

Předchozí obslužná rutina ověří operaci pomocí prostředku, identity uživatele a vlastnosti požadavku Name .

Výzva a zakázání obslužné rutiny provozního prostředku

V této části se dozvíte, jak se výsledky výzvy a zákazu akcí zpracovávají a jak se liší.

Chcete-li volat obslužnou rutinu provozního prostředku, zadejte operaci při vyvolání AuthorizeAsync v obslužné rutině nebo akci stránky. Následující příklad určuje, zda ověřený uživatel má povoleno zobrazit zadaný dokument.

Poznámka:

Následující ukázky kódu předpokládají, že se spustilo ověřování a nastavila User vlastnost.

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

Pokud autorizace proběhne úspěšně, vrátí se stránka pro zobrazení dokumentu. Pokud autorizace selže, ale uživatel se ověří, vrátí se informace ForbidResult o tom, že autorizace selhala. A ChallengeResult se vrátí, když se musí provést ověřování. U interaktivních klientů prohlížeče může být vhodné uživatele přesměrovat na přihlašovací stránku.

Přístup k autorizaci závisí na prostředku. Například k aktualizaci dokumentu má oprávnění pouze autor dokumentu. V důsledku toho musí být dokument načten z úložiště dat před vyhodnocením autorizace.

Vyhodnocení atributu probíhá před datovou vazbou a před spuštěním obslužné rutiny stránky nebo akce, která dokument načte. Z těchto důvodů nestačí deklarativní autorizace s atributem [Authorize] . Místo toho můžete vyvolat vlastní metodu autorizace – styl označovaný jako imperativní autorizace.

Zobrazení nebo stažení vzorového kódu (postup stažení)

Vytvoření aplikace ASP.NET Core s uživatelskými daty chráněnými autorizací obsahuje ukázkovou aplikaci, která používá autorizaci založenou na prostředcích.

Použití imperativní autorizace

Autorizace se implementuje jako IAuthorizationService služba a je zaregistrovaná v kolekci služeb v rámci Startup třídy. Služba je dostupná prostřednictvím injektáže závislostí pro obslužné rutiny nebo akce stránky.

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

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

IAuthorizationService má dvě AuthorizeAsync přetížení metod: jeden přijímá prostředek a název zásady a druhý přijímá prostředek a seznam požadavků k vyhodnocení.

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

V následujícím příkladu je prostředek, který se má zabezpečit, načten do vlastního Document objektu. Vyvolá AuthorizeAsync se přetížení, které určuje, jestli má aktuální uživatel povoleno upravovat zadaný dokument. Do rozhodnutí se zamítá vlastní zásady autorizace EditPolicy. Další informace o vytváření zásad autorizace najdete v tématu Vlastní autorizace na základě zásad.

Poznámka:

Následující ukázky kódu předpokládají, že se spustilo ověřování a nastavila User vlastnost.

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

Zápis obslužné rutiny založené na prostředcích

Zápis obslužné rutiny pro autorizaci na základě prostředků se moc neliší od zápisu obslužné rutiny prostých požadavků. Vytvořte vlastní třídu požadavků a implementujte třídu obslužné rutiny požadavku. Další informace o vytvoření třídy požadavků naleznete v tématu Požadavky.

Třída obslužné rutiny určuje požadavek i typ prostředku. Například obslužná rutina využívající SameAuthorRequirement prostředek a Document prostředek:

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

V předchozím příkladu si představte, že SameAuthorRequirement jde o speciální případ obecnější SpecificAuthorRequirement třídy. Třída SpecificAuthorRequirement (není zobrazena) obsahuje Name vlastnost představující jméno autora. Name Vlastnost může být nastavena na aktuálního uživatele.

Zaregistrujte požadavek a obslužnou rutinu v 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>();

Provozní požadavky

Pokud provádíte rozhodnutí na základě výsledků operací CRUD (vytvoření, čtení, aktualizace, odstranění), použijte pomocnou OperationAuthorizationRequirement třídu. Tato třída umožňuje psát jednu obslužnou rutinu místo jednotlivé třídy pro každý typ operace. Pokud ho chcete použít, zadejte několik názvů operací:

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

Obslužná rutina se implementuje následujícím způsobem pomocí OperationAuthorizationRequirement požadavku a Document prostředku:

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

Předchozí obslužná rutina ověří operaci pomocí prostředku, identity uživatele a vlastnosti požadavku Name .

Výzva a zakázání obslužné rutiny provozního prostředku

V této části se dozvíte, jak se výsledky výzvy a zákazu akcí zpracovávají a jak se liší.

Chcete-li volat obslužnou rutinu provozního prostředku, zadejte operaci při vyvolání AuthorizeAsync v obslužné rutině nebo akci stránky. Následující příklad určuje, zda ověřený uživatel má povoleno zobrazit zadaný dokument.

Poznámka:

Následující ukázky kódu předpokládají, že se spustilo ověřování a nastavila User vlastnost.

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

Pokud autorizace proběhne úspěšně, vrátí se stránka pro zobrazení dokumentu. Pokud autorizace selže, ale uživatel se ověří, vrátí se informace ForbidResult o tom, že autorizace selhala. A ChallengeResult se vrátí, když se musí provést ověřování. U interaktivních klientů prohlížeče může být vhodné uživatele přesměrovat na přihlašovací stránku.

Přístup k autorizaci závisí na prostředku. Například k aktualizaci dokumentu má oprávnění pouze autor dokumentu. V důsledku toho musí být dokument načten z úložiště dat před vyhodnocením autorizace.

Vyhodnocení atributu probíhá před datovou vazbou a před spuštěním obslužné rutiny stránky nebo akce, která dokument načte. Z těchto důvodů nestačí deklarativní autorizace s atributem [Authorize] . Místo toho můžete vyvolat vlastní metodu autorizace – styl označovaný jako imperativní autorizace.

Zobrazení nebo stažení vzorového kódu (postup stažení)

Vytvoření aplikace ASP.NET Core s uživatelskými daty chráněnými autorizací obsahuje ukázkovou aplikaci, která používá autorizaci založenou na prostředcích.

Použití imperativní autorizace

Autorizace se implementuje jako IAuthorizationService služba a je zaregistrovaná v kolekci služeb v rámci Startup třídy. Služba je dostupná prostřednictvím injektáže závislostí pro obslužné rutiny nebo akce stránky.

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

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

IAuthorizationService má dvě AuthorizeAsync přetížení metod: jeden přijímá prostředek a název zásady a druhý přijímá prostředek a seznam požadavků k vyhodnocení.

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

V následujícím příkladu je prostředek, který se má zabezpečit, načten do vlastního Document objektu. Vyvolá AuthorizeAsync se přetížení, které určuje, jestli má aktuální uživatel povoleno upravovat zadaný dokument. Do rozhodnutí se zamítá vlastní zásady autorizace EditPolicy. Další informace o vytváření zásad autorizace najdete v tématu Vlastní autorizace na základě zásad.

Poznámka:

Následující ukázky kódu předpokládají, že se spustilo ověřování a nastavila User vlastnost.

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

Zápis obslužné rutiny založené na prostředcích

Zápis obslužné rutiny pro autorizaci na základě prostředků se moc neliší od zápisu obslužné rutiny prostých požadavků. Vytvořte vlastní třídu požadavků a implementujte třídu obslužné rutiny požadavku. Další informace o vytvoření třídy požadavků naleznete v tématu Požadavky.

Třída obslužné rutiny určuje požadavek i typ prostředku. Například obslužná rutina využívající SameAuthorRequirement prostředek a Document prostředek:

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

V předchozím příkladu si představte, že SameAuthorRequirement jde o speciální případ obecnější SpecificAuthorRequirement třídy. Třída SpecificAuthorRequirement (není zobrazena) obsahuje Name vlastnost představující jméno autora. Name Vlastnost může být nastavena na aktuálního uživatele.

Zaregistrujte požadavek a obslužnou rutinu v 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>();

Provozní požadavky

Pokud provádíte rozhodnutí na základě výsledků operací CRUD (vytvoření, čtení, aktualizace, odstranění), použijte pomocnou OperationAuthorizationRequirement třídu. Tato třída umožňuje psát jednu obslužnou rutinu místo jednotlivé třídy pro každý typ operace. Pokud ho chcete použít, zadejte několik názvů operací:

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

Obslužná rutina se implementuje následujícím způsobem pomocí OperationAuthorizationRequirement požadavku a Document prostředku:

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

Předchozí obslužná rutina ověří operaci pomocí prostředku, identity uživatele a vlastnosti požadavku Name .

Výzva a zakázání obslužné rutiny provozního prostředku

V této části se dozvíte, jak se výsledky výzvy a zákazu akcí zpracovávají a jak se liší.

Chcete-li volat obslužnou rutinu provozního prostředku, zadejte operaci při vyvolání AuthorizeAsync v obslužné rutině nebo akci stránky. Následující příklad určuje, zda ověřený uživatel má povoleno zobrazit zadaný dokument.

Poznámka:

Následující ukázky kódu předpokládají, že se spustilo ověřování a nastavila User vlastnost.

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

Pokud autorizace proběhne úspěšně, vrátí se stránka pro zobrazení dokumentu. Pokud autorizace selže, ale uživatel se ověří, vrátí se informace ForbidResult o tom, že autorizace selhala. A ChallengeResult se vrátí, když se musí provést ověřování. U interaktivních klientů prohlížeče může být vhodné uživatele přesměrovat na přihlašovací stránku.