ASP.NET Core'de ilke tabanlı yetkilendirme

Rol tabanlı yetkilendirme ve talep tabanlı yetkilendirme, bir gereksinim, gereksinim işleyicisi ve önceden yapılandırılmış bir ilkeyi kapsar. Bu yapı taşları, kodda yetkilendirme değerlendirmelerinin ifadesini destekler. Sonuç daha zengin, yeniden kullanılabilir, test edilebilir bir yetkilendirme yapısıdır.

Yetkilendirme ilkesi bir veya daha fazla gereksinimlerden oluşur. Yetkilendirme hizmeti yapılandırmasının bir parçası olarak uygulamanın Program.cs dosyasına kaydedin:

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

Önceki örnekte bir "AtLeast21" ilkesi oluşturulur. En düşük yaşa sahip olan ve gereksinime parametre — olarak sağlanan tek bir gereksinimi vardır.

IAuthorizationService

Yetkilendirmenin başarılı olup olmadığını belirleyen birincil IAuthorizationService hizmet:

/// <summary>
/// Checks policy based permissions for a user
/// </summary>
public interface IAuthorizationService
{
    /// <summary>
    /// Checks if a user meets a specific set of requirements for the specified resource
    /// </summary>
    /// <param name="user">The user to evaluate the requirements against.</param>
    /// <param name="resource">
    /// An optional resource the policy should be checked with.
    /// If a resource is not required for policy evaluation you may pass null as the value
    /// </param>
    /// <param name="requirements">The requirements to evaluate.</param>
    /// <returns>
    /// A flag indicating whether authorization has succeeded.
    /// This value is <value>true</value> when the user fulfills the policy; 
    /// otherwise <value>false</value>.
    /// </returns>
    /// <remarks>
    /// Resource is an optional parameter and may be null. Please ensure that you check 
    /// it is not null before acting upon it.
    /// </remarks>
    Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, 
                                     IEnumerable<IAuthorizationRequirement> requirements);

    /// <summary>
    /// Checks if a user meets a specific authorization policy
    /// </summary>
    /// <param name="user">The user to check the policy against.</param>
    /// <param name="resource">
    /// An optional resource the policy should be checked with.
    /// If a resource is not required for policy evaluation you may pass null as the value
    /// </param>
    /// <param name="policyName">The name of the policy to check against a specific 
    /// context.</param>
    /// <returns>
    /// A flag indicating whether authorization has succeeded.
    /// Returns a flag indicating whether the user, and optional resource has fulfilled 
    /// the policy.    
    /// <value>true</value> when the policy has been fulfilled; 
    /// otherwise <value>false</value>.
    /// </returns>
    /// <remarks>
    /// Resource is an optional parameter and may be null. Please ensure that you check
    /// it is not null before acting upon it.
    /// </remarks>
    Task<AuthorizationResult> AuthorizeAsync(
                                ClaimsPrincipal user, object resource, string policyName);
}

Yukarıdaki kod, IAuthorizationService'in iki yöntemini vurgular.

IAuthorizationRequirement , yöntem olmadan bir işaretçi hizmeti ve yetkilendirmenin başarılı olup olmadığını izleme mekanizmasıdır.

Her IAuthorizationHandler biri gereksinimlerin karşı olup olamaylarını denetlemeden sorumludur:

/// <summary>
/// Classes implementing this interface are able to make a decision if authorization
/// is allowed.
/// </summary>
public interface IAuthorizationHandler
{
    /// <summary>
    /// Makes a decision if authorization is allowed.
    /// </summary>
    /// <param name="context">The authorization information.</param>
    Task HandleAsync(AuthorizationHandlerContext context);
}

sınıf, AuthorizationHandlerContext işleyicinin gereksinimlerin karşı olup olmadığını işaretlemek için kullandığı sınıftır:

 context.Succeed(requirement)

Aşağıdaki kod, yetkilendirme hizmetinin basitleştirilmiş (ve açıklamalarla açıklamalı) varsayılan uygulamasını gösterir:

public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, 
             object resource, IEnumerable<IAuthorizationRequirement> requirements)
{
    // Create a tracking context from the authorization inputs.
    var authContext = _contextFactory.CreateContext(requirements, user, resource);

    // By default this returns an IEnumerable<IAuthorizationHandlers> from DI.
    var handlers = await _handlers.GetHandlersAsync(authContext);

    // Invoke all handlers.
    foreach (var handler in handlers)
    {
        await handler.HandleAsync(authContext);
    }

    // Check the context, by default success is when all requirements have been met.
    return _evaluator.Evaluate(authContext);
}

Aşağıdaki kod tipik bir yetkilendirme hizmeti yapılandırmasını gösterir:

// Add all of your handlers to DI.
builder.Services.AddSingleton<IAuthorizationHandler, MyHandler1>();
// MyHandler2, ...

builder.Services.AddSingleton<IAuthorizationHandler, MyHandlerN>();

// Configure your policies
builder.Services.AddAuthorization(options =>
      options.AddPolicy("Something",
      policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything")));

Yetkilendirme IAuthorizationService için , veya [Authorize(Policy = "Something")] RequireAuthorization("Something") kullanın.

MVC denetleyicilerine ilke uygulama

Sayfalar kullanan uygulamalar Razor için İlkeleri Sayfalara uygulama Razor bölümüne bakın.

İlke adıyla özniteliğini kullanarak [Authorize] denetleyicilere ilkeler uygulama. Örnek:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace AuthorizationPoliciesSample.Controllers;

[Authorize(Policy = "AtLeast21")]
public class AtLeast21Controller : Controller
{
    public IActionResult Index() => View();
}

Sayfalara ilke Razor uygulama

İlke adıyla Razor özniteliğini kullanarak [Authorize] Sayfalara ilkeler uygulama. Örnek:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace AuthorizationPoliciesSample.Pages;

[Authorize(Policy = "AtLeast21")]
public class AtLeast21Model : PageModel { }

İlkeler Sayfa Razor işleyici düzeyinde uygulanamamalıdır, bu ilkeler Sayfaya uygulanmalıdır.

İlkeler, bir yetkilendirme Razor kuralı kullanılarak Sayfalara da uygulanabilir.

Uç noktalara ilke uygulama

İlke adıyla kullanarak uç RequireAuthorization noktalara ilkeler uygulama. Örnek:

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

Gereksinimler

Yetkilendirme gereksinimi, bir ilkenin geçerli kullanıcı sorumlularını değerlendirmek için kullanabileceği veri parametreleri koleksiyonudur. "AtLeast21" ilkemizde gereksinim, yaş sınırı için tek — bir parametredir. Bir gereksinim, boş bir işaretçi arabirimi olan IAuthorizationRequirement'iuygulamaya almaktadır. Parametreli bir minimum yaş gereksinimi aşağıdaki gibi uygulanabilirsiniz:

using Microsoft.AspNetCore.Authorization;

namespace AuthorizationPoliciesSample.Policies.Requirements;

public class MinimumAgeRequirement : IAuthorizationRequirement
{
    public MinimumAgeRequirement(int minimumAge) =>
        MinimumAge = minimumAge;

    public int MinimumAge { get; }
}

Bir yetkilendirme ilkesi birden çok yetkilendirme gereksinimlerini içeriyorsa, ilke değerlendirmesinin başarılı olması için tüm gereksinimlerin geçmesi gerekir. Başka bir deyişle, tek bir yetkilendirme ilkesine eklenen birden çok yetkilendirme gereksinimleri AND temelinde kabul edilir.

Not

Bir gereksinimde veri veya özellik olması gerekli değildir.

Yetkilendirme işleyicileri

Yetkilendirme işleyicisi, bir gereksinimin özelliklerinin değerlendirilmesinden sorumludur. Yetkilendirme işleyicisi, erişime izin verili olup olmadığını belirlemek için sağlanan AuthorizationHandlerContext'e göre gereksinimleri değerlendirir.

Bir gereksinim birden çok işleyiciye sahip olabilir. İşleyici AuthorizationHandler'i devralabilir; <TRequirement> TRequirement burada işleyicinin gerekli olması gerekir. Alternatif olarak, bir işleyici birden fazla gereksinim türünü işlemek için IAuthorizationHandler'i doğrudan gerçekleştirebilir.

Bir gereksinim için işleyici kullanma

Aşağıdaki örnekte, en küçük yaş işleyicisi tek bir gereksinimi işleyen bire bir ilişki gösterir:

using System.Security.Claims;
using AuthorizationPoliciesSample.Policies.Requirements;
using Microsoft.AspNetCore.Authorization;

namespace AuthorizationPoliciesSample.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 && c.Issuer == "http://contoso.com");

        if (dateOfBirthClaim is null)
        {
            return Task.CompletedTask;
        }

        var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value);
        int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
        if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
        {
            calculatedAge--;
        }

        if (calculatedAge >= requirement.MinimumAge)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

Yukarıdaki kod, geçerli kullanıcı sorumlusuna bilinen ve güvenilen bir Yayın yapan tarafından verilen bir doğum tarihi talebi olup olmadığını belirler. Talep eksik olduğunda yetkilendirme meydana gelebilir ve bu durumda tamamlanmış bir görev döndürülür. Talep olduğunda kullanıcının yaşı hesaplanır. Kullanıcı gereksinim tarafından tanımlanan en düşük yaşı karşılarsa, yetkilendirme başarılı kabul edildi. Yetkilendirme başarılı olduğunda, context.Succeed tek parametresi olarak karşılan gereksinimle çağrılır.

Birden çok gereksinimler için işleyici kullanma

Aşağıdaki örnekte, izin işleyicisi üç farklı tür gereksinimleri işleyene bire çok ilişkisi gösterir:

using System.Security.Claims;
using AuthorizationPoliciesSample.Policies.Requirements;
using Microsoft.AspNetCore.Authorization;

namespace AuthorizationPoliciesSample.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;
    }
}

Yukarıdaki kod PendingRequirementsiçinde başarılı — olarak işaretlenen gereksinimleri içeren bir özelliktir. Bir ReadPermission gereksinim için kullanıcının istenen kaynağa erişmek için sahip veya sponsor olması gerekir. Bir veya gereksinimi EditPermission DeletePermission durumunda, istenen kaynağa erişmek için sahip olması gerekir.

İşleyici kaydı

Yapılandırma sırasında hizmet koleksiyonunda işleyicileri kaydetme. Örnek:

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

Yukarıdaki kod tek MinimumAgeHandler bir kod olarak kaydedmektedir. İşleyiciler yerleşik hizmet yaşam sürelerinin herhangi biri kullanılarak kayded olabilir.

Hem bir gereksinimi hem de işleyicisini hem hem de uygulayan tek bir sınıfa paket uygulamak IAuthorizationRequirement IAuthorizationHandler mümkündür. Bu, işleyici ile gereksinim arasında sıkı bir eşleşme oluşturur ve yalnızca basit gereksinimler ve işleyiciler için önerilir. Her iki arabirimi de uygulayan bir sınıf oluşturmak, gereksinimlerin kendilerini işlemesini sağlayan yerleşik PassThroughAuthorizationHandler nedeniyle işleyiciyi DI'ye kaydetme ihtiyacı ortadan kaldırır.

Tam olarak kendi içinde bulunan bir sınıfta hem gereksinim hem de işleyici olduğu iyi bir örnek için AssertionRequirement AssertionRequirement sınıfına bakın.

İşleyici ne getirsin?

İşleyici Handle örneğinde yönteminin değer döndüre olmadığını unutmayın. Başarı veya başarısızlık durumu nasıl belirtilmiştir?

  • İşleyici, çağrılarak context.Succeed(IAuthorizationRequirement requirement) başarıyla doğrulanmış gereksinimini geçerek başarılı olduğunu gösterir.

  • Bir işleyicinin genellikle hataları işlemesi gerekli değildir çünkü aynı gereksinime sahip diğer işleyiciler başarılı olabilir.

  • Başarısızlığı garanti etmek için, diğer gereksinim işleyicileri başarılı olsa bile context.Fail çağrısı.

Bir işleyici veya context.Succeed context.Fail çağrısında olursa diğer tüm işleyiciler çağrılır. Bu, başka bir işleyici bir gereksinimi başarıyla doğrulasa veya başarısız olsa bile gereksinimlerini günlüğe kaydetme gibi yan etkiler üretmeye olanak sağlar. olarak false ayarlanırsa InvokeHandlersAfterFailure özelliği, çağrıldığında işleyicilerin yürütülmesini kısa context.Fail devreler. InvokeHandlersAfterFailure , varsayılan olarak true kullanılır ve bu durumda tüm işleyiciler çağrılır.

Not

Kimlik doğrulaması başarısız olsa bile yetkilendirme işleyicileri çağrılır.

Bir gereksinim için neden birden çok işleyiciyi istiyorum?

Değerlendirmenin BIR VEYA temelinde olması istediğiniz durumlarda, tek bir gereksinim için birden çok işleyiciyi uygulama. Örneğin, Microsoft'un yalnızca anahtar kartlarıyla açık olan kapıları vardır. Anahtar kartınızı evde bırakırsanız, sinyal uzmanı geçici bir etiket yazdırır ve sizin için kapı açar. Bu senaryoda Tek bir gereksinim (BuildingEntry) vardır ancak her biri tek bir gereksinimi incelerken birden çok işleyici vardır.

BuildingEntryRequirement.cs

using Microsoft.AspNetCore.Authorization;

namespace AuthorizationPoliciesSample.Policies.Requirements;

public class BuildingEntryRequirement : IAuthorizationRequirement { }

BadgeEntryHandler.cs

using AuthorizationPoliciesSample.Policies.Requirements;
using Microsoft.AspNetCore.Authorization;

namespace AuthorizationPoliciesSample.Policies.Handlers;

public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context, BuildingEntryRequirement requirement)
    {
        if (context.User.HasClaim(
            c => c.Type == "BadgeId" && c.Issuer == "https://microsoftsecurity"))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

TemporaryStickerHandler.cs

using AuthorizationPoliciesSample.Policies.Requirements;
using Microsoft.AspNetCore.Authorization;

namespace AuthorizationPoliciesSample.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://microsoftsecurity"))
        {
            // Code to check expiration date omitted for brevity.
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

Her iki işleyicinin de kayıtlı olduğundan emin olun. bir ilke değerlendirmesi olduğunda her iki işleyiciden biri başarılı BuildingEntryRequirement olursa, ilke değerlendirmesi başarılı olur.

İlkeyi yerine getirmek için func kullanma

Bir ilkenin yerine getirilmesinin kodda ifade etmek kolay olduğu durumlar olabilir. İlke oluşturucu ile Func<AuthorizationHandlerContext, bool> bir ilke yapılandıran bir sağlamak RequireAssertion mümkündür.

Örneğin, önceki aşağıdaki BadgeEntryHandler gibi yeniden yazılabilir:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("BadgeEntry", policy =>
        policy.RequireAssertion(context => context.User.HasClaim(c =>
            (c.Type == "BadgeId" || c.Type == "TemporaryBadgeId")
            && c.Issuer == "https://microsoftsecurity")));
});

İşleyicilerde MVC istek bağlamına erişme

yöntemi HandleRequirementAsync iki parametreye sahip: ve AuthorizationHandlerContextTRequirement ediliyor. MVC gibi çerçeveler veya SignalR ek bilgi geçmek için Resource özelliğine herhangi bir nesne AuthorizationHandlerContext eklemekte serbesttir.

Uç nokta yönlendirmesi kullanılırken yetkilendirme genellikle Yetkilendirme Ara Yazılımı tarafından uygulanır. Bu durumda özelliği Resource bir HttpContext örneğidir. Bağlam geçerli uç noktasına erişmek için kullanılabilir ve bu da yönlendirmede bulunarak temel alınan kaynağı yoklamada kullanılabilir. Örnek:

if (context.Resource is HttpContext httpContext)
{
    var endpoint = httpContext.GetEndpoint();
    var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
    ...
}

Geleneksel yönlendirmede veya yetkilendirme MVC'nin yetkilendirme filtresinin bir parçası olarak gerçekleşirse değeri Resource bir AuthorizationFilterContext örnektir. Bu özellik, HttpContext , ve RouteData MVC ve Pages tarafından sağlanan diğer her şeye erişim Razor sağlar.

özelliğinin kullanımı Resource çerçeveye özgü bir özelliktir. özelliğinde bilgi Resource kullanmak, yetkilendirme ilkelerinizi belirli çerçeveler ile sınırlar. özelliğini anahtar sözcüğünü kullanarak çalıştırmanız ve ardından kodunuzun diğer çerçevelerde çalıştırıldıklarda ile kilitlenmey olduğundan emin olmak için cast işleminin başarılı Resource is olduğunu InvalidCastException onaylamanız gerekir:

// Requires the following import:
//     using Microsoft.AspNetCore.Mvc.Filters;
if (context.Resource is AuthorizationFilterContext mvcContext)
{
    // Examine MVC-specific things like routing data.
}

Tüm kullanıcıların kimlik doğrulamasının genel olarak gerekli olması

Tüm kullanıcıların kimliklerinin nasıl doğrulandığını öğrenmek için bkz. kimliği doğrulanmış kullanıcılar gerektirme.

Rol tabanlı yetkilendirme ve talep tabanlı yetkilendirme, bir gereksinim, gereksinim işleyicisi ve önceden yapılandırılmış bir ilkeyi kapsar. Bu yapı taşları, kodda yetkilendirme değerlendirmelerinin ifadesini destekler. Sonuç daha zengin, yeniden kullanılabilir, test edilebilir bir yetkilendirme yapısıdır.

Yetkilendirme ilkesi bir veya daha fazla gereksinimlerden oluşur. Yetkilendirme hizmeti yapılandırmasının bir parçası olarak yöntemine Startup.ConfigureServices kaydedilir:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();
    services.AddAuthorization(options =>
    {
        options.AddPolicy("AtLeast21", policy =>
            policy.Requirements.Add(new MinimumAgeRequirement(21)));
    });
}

Yukarıdaki örnekte bir "AtLeast21" ilkesi oluşturulur. En düşük yaşa sahip olan ve gereksinime parametre — olarak sağlanan tek bir gereksinimi vardır.

IAuthorizationService

Yetkilendirmenin başarılı olup olmadığını belirleyen birincil IAuthorizationService hizmet:

/// <summary>
/// Checks policy based permissions for a user
/// </summary>
public interface IAuthorizationService
{
    /// <summary>
    /// Checks if a user meets a specific set of requirements for the specified resource
    /// </summary>
    /// <param name="user">The user to evaluate the requirements against.</param>
    /// <param name="resource">
    /// An optional resource the policy should be checked with.
    /// If a resource is not required for policy evaluation you may pass null as the value
    /// </param>
    /// <param name="requirements">The requirements to evaluate.</param>
    /// <returns>
    /// A flag indicating whether authorization has succeeded.
    /// This value is <value>true</value> when the user fulfills the policy; 
    /// otherwise <value>false</value>.
    /// </returns>
    /// <remarks>
    /// Resource is an optional parameter and may be null. Please ensure that you check 
    /// it is not null before acting upon it.
    /// </remarks>
    Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, 
                                     IEnumerable<IAuthorizationRequirement> requirements);

    /// <summary>
    /// Checks if a user meets a specific authorization policy
    /// </summary>
    /// <param name="user">The user to check the policy against.</param>
    /// <param name="resource">
    /// An optional resource the policy should be checked with.
    /// If a resource is not required for policy evaluation you may pass null as the value
    /// </param>
    /// <param name="policyName">The name of the policy to check against a specific 
    /// context.</param>
    /// <returns>
    /// A flag indicating whether authorization has succeeded.
    /// Returns a flag indicating whether the user, and optional resource has fulfilled 
    /// the policy.    
    /// <value>true</value> when the policy has been fulfilled; 
    /// otherwise <value>false</value>.
    /// </returns>
    /// <remarks>
    /// Resource is an optional parameter and may be null. Please ensure that you check
    /// it is not null before acting upon it.
    /// </remarks>
    Task<AuthorizationResult> AuthorizeAsync(
                                ClaimsPrincipal user, object resource, string policyName);
}

Yukarıdaki kod, IAuthorizationService'in iki yöntemini vurgular.

IAuthorizationRequirement , yöntem olmadan bir işaretçi hizmeti ve yetkilendirmenin başarılı olup olmadığını izleme mekanizmasıdır.

Her IAuthorizationHandler biri gereksinimlerin karşı mı olduğunu kontrol etmekle sorumludur:

/// <summary>
/// Classes implementing this interface are able to make a decision if authorization
/// is allowed.
/// </summary>
public interface IAuthorizationHandler
{
    /// <summary>
    /// Makes a decision if authorization is allowed.
    /// </summary>
    /// <param name="context">The authorization information.</param>
    Task HandleAsync(AuthorizationHandlerContext context);
}

sınıf, AuthorizationHandlerContext işleyicinin gereksinimlerin karşı olup olmadığını işaretlemek için kullandığı sınıftır:

 context.Succeed(requirement)

Aşağıdaki kod, yetkilendirme hizmetinin basitleştirilmiş (ve açıklamalarla açıklamalı) varsayılan uygulamasını gösterir:

public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, 
             object resource, IEnumerable<IAuthorizationRequirement> requirements)
{
    // Create a tracking context from the authorization inputs.
    var authContext = _contextFactory.CreateContext(requirements, user, resource);

    // By default this returns an IEnumerable<IAuthorizationHandlers> from DI.
    var handlers = await _handlers.GetHandlersAsync(authContext);

    // Invoke all handlers.
    foreach (var handler in handlers)
    {
        await handler.HandleAsync(authContext);
    }

    // Check the context, by default success is when all requirements have been met.
    return _evaluator.Evaluate(authContext);
}

Aşağıdaki kod tipik bir ConfigureServices gösterir:

public void ConfigureServices(IServiceCollection services)
{
    // Add all of your handlers to DI.
    services.AddSingleton<IAuthorizationHandler, MyHandler1>();
    // MyHandler2, ...

    services.AddSingleton<IAuthorizationHandler, MyHandlerN>();

    // Configure your policies
    services.AddAuthorization(options =>
          options.AddPolicy("Something",
          policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything")));


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

Yetkilendirme IAuthorizationService için veya [Authorize(Policy = "Something")] kullanın.

MVC denetleyicilerine ilke uygulama

Sayfalar'ı Razor kullanıyorsanız bu belgede Yer alan Sayfalara Razor ilke uygulama'ya bakın.

İlkeler, ilke adıyla özniteliği [Authorize] kullanılarak denetleyicilere uygulanır. Örnek:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[Authorize(Policy = "AtLeast21")]
public class AlcoholPurchaseController : Controller
{
    public IActionResult Index() => View();
}

Sayfalara ilke Razor uygulama

İlkeler, Razor ilke adıyla özniteliği kullanılarak [Authorize] Sayfalar'a uygulanır. Örnek:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;

[Authorize(Policy = "AtLeast21")]
public class AlcoholPurchaseModel : PageModel
{
}

İlkeler Sayfa Razor işleyici düzeyinde uygulanamamalıdır, bu ilkeler Sayfaya uygulanmalıdır.

İlkeler, bir Razor yetkilendirme kuralı kullanılarak Sayfalara uygulanabilir.

Gereksinimler

Yetkilendirme gereksinimi, bir ilkenin geçerli kullanıcı sorumlularını değerlendirmek için kullanabileceği veri parametreleri koleksiyonudur. "AtLeast21" ilkemizde gereksinim, yaş sınırı için tek — bir parametredir. Bir gereksinim, boş bir işaretçi arabirimi olan IAuthorizationRequirement'iuygulamaya almaktadır. Parametreli bir minimum yaş gereksinimi aşağıdaki gibi uygulanabilirsiniz:

using Microsoft.AspNetCore.Authorization;

public class MinimumAgeRequirement : IAuthorizationRequirement
{
    public int MinimumAge { get; }

    public MinimumAgeRequirement(int minimumAge)
    {
        MinimumAge = minimumAge;
    }
}

Bir yetkilendirme ilkesi birden çok yetkilendirme gereksinimlerini içeriyorsa, ilke değerlendirmesinin başarılı olması için tüm gereksinimlerin geçmesi gerekir. Başka bir deyişle, tek bir yetkilendirme ilkesine eklenen birden çok yetkilendirme gereksinimleri AND temelinde kabul edilir.

Not

Bir gereksinimde veri veya özellik olması gerekli değildir.

Yetkilendirme işleyicileri

Yetkilendirme işleyicisi, bir gereksinimin özelliklerinin değerlendirilmesinden sorumludur. Yetkilendirme işleyicisi, erişime izin verili olup olmadığını belirlemek için sağlanan AuthorizationHandlerContext'e göre gereksinimleri değerlendirir.

Bir gereksinim birden çok işleyiciye sahip olabilir. İşleyici AuthorizationHandler'i devralabilir; <TRequirement> TRequirement burada işleyicinin gerekli olması gerekir. Alternatif olarak, bir işleyici birden fazla gereksinim türünü işlemek için IAuthorizationHandler'i gerçekleştirebilir.

Bir gereksinim için işleyici kullanma

Aşağıda, en küçük yaş işleyicisi tek bir gereksinimden yararlanan bire bir ilişkiye örnektir:

using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;

public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   MinimumAgeRequirement requirement)
    {
        if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth &&
                                        c.Issuer == "http://contoso.com"))
        {
            //TODO: 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 && 
                                        c.Issuer == "http://contoso.com").Value);

        int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
        if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
        {
            calculatedAge--;
        }

        if (calculatedAge >= requirement.MinimumAge)
        {
            context.Succeed(requirement);
        }

        //TODO: Use the following if targeting a version of
        //.NET Framework older than 4.6:
        //      return Task.FromResult(0);
        return Task.CompletedTask;
    }
}

Yukarıdaki kod, geçerli kullanıcı sorumlusuna bilinen ve güvenilen bir Yayın yapan tarafından verilen bir doğum tarihi talebi olup olmadığını belirler. Talep eksik olduğunda yetkilendirme meydana gelebilir ve bu durumda tamamlanmış bir görev döndürülür. Talep olduğunda kullanıcının yaşı hesaplanır. Kullanıcı gereksinim tarafından tanımlanan en düşük yaşı karşılarsa, yetkilendirme başarılı kabul olur. Yetkilendirme başarılı olduğunda, context.Succeed tek parametresi olarak karşılan gereksinimle çağrılır.

Birden çok gereksinimler için işleyici kullanma

Aşağıda, bir izin işleyicinin üç farklı tür gereksinimlerini işleyene bire çok ilişkisine bir örnek ve ardından ve bire çok ilişkisi yer alacaktır:

using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;

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

        //TODO: 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;
    }
}

Yukarıdaki kod PendingRequirementsiçinde başarılı — olarak işaretlenen gereksinimleri içeren bir özelliktir. Bir ReadPermission gereksinim için kullanıcının istenen kaynağa erişmesi için sahip veya sponsor olması gerekir. Bir veya gereksinimi EditPermission olması DeletePermission durumunda, istenen kaynağa erişmek için bir sahip olması gerekir.

İşleyici kaydı

İşleyiciler yapılandırma sırasında hizmetler koleksiyonuna kaydedilir. Örnek:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();
    services.AddAuthorization(options =>
    {
        options.AddPolicy("AtLeast21", policy =>
            policy.Requirements.Add(new MinimumAgeRequirement(21)));
    });

    services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
}

Yukarıdaki kod, MinimumAgeHandler 'i kullanarak tek bir kod olarak services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>(); kaydoluyor. İşleyiciler yerleşik hizmet yaşam sürelerinin herhangi biri kullanılarak kayded olabilir.

Hem hem de uygulayan tek bir sınıfta hem bir gereksinimi hem de işleyiciyi paket olarak IAuthorizationRequirement IAuthorizationHandler kullanabilirsiniz. Bu, işleyici ile gereksinim arasında sıkı bir eşleşme oluşturur ve yalnızca basit gereksinimler ve işleyiciler için önerilir. Her iki arabirimi de uygulayan bir sınıf oluşturmak, gereksinimlerin kendilerini işlemesini sağlayan yerleşik PassThroughAuthorizationHandler nedeniyle işleyiciyi DI'ye kaydetme ihtiyacı ortadan kaldırır.

Tam olarak kendi içinde bulunan bir sınıfta hem gereksinim hem de işleyici olduğu iyi bir örnek için AssertionRequirement AssertionRequirement sınıfına bakın.

İşleyici ne getirsin?

İşleyici Handle örneğinde yönteminin değer döndüreni olmadığını unutmayın. Başarı veya başarısızlık durumu nasıl belirtilmiştir?

  • İşleyici, çağrılarak context.Succeed(IAuthorizationRequirement requirement) başarıyla doğrulanmış gereksinimini geçerek başarılı olduğunu gösterir.

  • Bir işleyicinin genellikle hataları işlemesi gerekli değildir çünkü aynı gereksinime sahip diğer işleyiciler başarılı olabilir.

  • Başarısızlığı garanti etmek için, diğer gereksinim işleyicileri başarılı olsa bile context.Fail çağrısı.

Bir işleyici veya context.Succeed context.Fail çağrısında olursa diğer tüm işleyiciler çağrılır. Bu, başka bir işleyici bir gereksinimi başarıyla doğrulasa veya başarısız olsa bile gereksinimlerini günlüğe kaydetme gibi yan etkiler üretmeye olanak sağlar. olarak false ayarlanırsa InvokeHandlersAfterFailure özelliği, çağrıldığında işleyicilerin yürütülmesini kısa context.Fail devreler. InvokeHandlersAfterFailure , varsayılan olarak true kullanılır ve bu durumda tüm işleyiciler çağrılır.

Not

Kimlik doğrulaması başarısız olsa bile yetkilendirme işleyicileri çağrılır.

Bir gereksinim için neden birden çok işleyiciyi istiyorum?

Değerlendirmenin BIR VEYA temelinde olması istediğiniz durumlarda, tek bir gereksinim için birden çok işleyiciyi uygulama. Örneğin, Microsoft'un yalnızca anahtar kartlarıyla açık olan kapıları vardır. Anahtar kartınızı evde bırakırsanız, sinyal uzmanı geçici bir etiket yazdırır ve sizin için kapı açar. Bu senaryoda Tek bir gereksinim (BuildingEntry) vardır ancak her biri tek bir gereksinimi incelerken birden çok işleyici vardır.

BuildingEntryRequirement.cs

using Microsoft.AspNetCore.Authorization;

public class BuildingEntryRequirement : IAuthorizationRequirement
{
}

BadgeEntryHandler.cs

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;

public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   BuildingEntryRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "BadgeId" &&
                                       c.Issuer == "http://microsoftsecurity"))
        {
            context.Succeed(requirement);
        }

        //TODO: 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.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;

public class TemporaryStickerHandler : AuthorizationHandler<BuildingEntryRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, 
                                                   BuildingEntryRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "TemporaryBadgeId" &&
                                       c.Issuer == "https://microsoftsecurity"))
        {
            // We'd also check the expiration date on the sticker.
            context.Succeed(requirement);
        }

        //TODO: Use the following if targeting a version of
        //.NET Framework older than 4.6:
        //      return Task.FromResult(0);
        return Task.CompletedTask;
    }
}

Her iki işleyicinin de kayıtlı olduğundan emin olun. bir ilke değerlendirmesi olduğunda işleyiciden biri başarılı BuildingEntryRequirement olursa, ilke değerlendirmesi başarılı olur.

İlkeyi yerine getirmek için func kullanma

Bir ilkenin yerine getirilmesinin kodda ifade etmek kolay olduğu durumlar olabilir. İlke oluşturucu ile Func<AuthorizationHandlerContext, bool> ilkenizi yapılandırarak bir RequireAssertion s sağlamak mümkündür.

Örneğin, önceki aşağıdaki BadgeEntryHandler gibi yeniden yazılabilir:

services.AddAuthorization(options =>
{
     options.AddPolicy("BadgeEntry", policy =>
        policy.RequireAssertion(context =>
            context.User.HasClaim(c =>
                (c.Type == "BadgeId" ||
                 c.Type == "TemporaryBadgeId") &&
                 c.Issuer == "https://microsoftsecurity")));
});

İşleyicilerde MVC istek bağlamına erişme

Yetkilendirme HandleRequirementAsync işleyicisinde uygulayan yöntemin iki parametresi vardır: bir AuthorizationHandlerContext ve TRequirement işleçleri. MVC gibi çerçeveler veya SignalR ek bilgi geçmek için Resource özelliğine herhangi bir nesne AuthorizationHandlerContext eklemekte serbesttir.

Uç nokta yönlendirmesi kullanılırken yetkilendirme genellikle Yetkilendirme Ara Yazılımı tarafından uygulanır. Bu durumda özelliği Resource bir HttpContext örneğidir. Bağlam geçerli uç noktasına erişmek için kullanılabilir ve bu da yönlendirmede bulunarak temel alınan kaynağı yoklamada kullanılabilir. Örnek:

if (context.Resource is HttpContext httpContext)
{
    var endpoint = httpContext.GetEndpoint();
    var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
    ...
}

Geleneksel yönlendirmede veya yetkilendirme MVC'nin yetkilendirme filtresinin bir parçası olarak gerçekleşirse değeri Resource bir AuthorizationFilterContext örnektir. Bu özellik, , HttpContext ve RouteData MVC ve Pages tarafından sağlanan diğer her şeye erişim Razor sağlar.

özelliğinin kullanımı Resource çerçeveye özgü bir özelliktir. özelliğinde bilgi Resource kullanmak, yetkilendirme ilkelerinizi belirli çerçeveler ile sınırlar. ResourceAnahtar sözcüğünü kullanarak özelliği atamalısınız is ve sonra, kodunuzun InvalidCastException diğer çerçeveler üzerinde çalıştırıldığında bir ile çökmemesini sağlamak için dönüştürmenin başarılı olduğunu doğrulayın:

// Requires the following import:
//     using Microsoft.AspNetCore.Mvc.Filters;
if (context.Resource is AuthorizationFilterContext mvcContext)
{
    // Examine MVC-specific things like routing data.
}

Genel olarak tüm kullanıcıların kimliğinin doğrulanmasını gerektir

Tüm kullanıcıların kimliklerinin nasıl doğrulandığını öğrenmek için bkz. kimliği doğrulanmış kullanıcılar gerektirme.

Kapakların altında rol tabanlı yetkilendirme ve talep tabanlı yetkilendirme , bir gereksinim, gereksinim işleyicisi ve önceden yapılandırılmış bir ilke kullanır. Bu yapı taşları, koddaki yetkilendirme değerlendirmeleri ifadesini destekler. Sonuç daha zengin, yeniden kullanılabilir ve test edilebilir bir yetkilendirme yapısıdır.

Yetkilendirme ilkesi bir veya daha fazla gereksinimden oluşur. Bu, yetkilendirme hizmeti yapılandırmasının bir parçası olarak kaydedilir, Startup.ConfigureServices yöntemi:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();
    services.AddAuthorization(options =>
    {
        options.AddPolicy("AtLeast21", policy =>
            policy.Requirements.Add(new MinimumAgeRequirement(21)));
    });
}

Yukarıdaki örnekte, "AtLeast21" ilkesi oluşturulur. Bu, — gereksinimle bir parametre olarak sağlanan minimum Age 'in tek bir gereksinimine sahiptir.

IAuthorizationService

Yetkilendirmenin başarılı olup olmadığını belirleyen birincil hizmet IAuthorizationService :

/// <summary>
/// Checks policy based permissions for a user
/// </summary>
public interface IAuthorizationService
{
    /// <summary>
    /// Checks if a user meets a specific set of requirements for the specified resource
    /// </summary>
    /// <param name="user">The user to evaluate the requirements against.</param>
    /// <param name="resource">
    /// An optional resource the policy should be checked with.
    /// If a resource is not required for policy evaluation you may pass null as the value
    /// </param>
    /// <param name="requirements">The requirements to evaluate.</param>
    /// <returns>
    /// A flag indicating whether authorization has succeeded.
    /// This value is <value>true</value> when the user fulfills the policy; 
    /// otherwise <value>false</value>.
    /// </returns>
    /// <remarks>
    /// Resource is an optional parameter and may be null. Please ensure that you check 
    /// it is not null before acting upon it.
    /// </remarks>
    Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, 
                                     IEnumerable<IAuthorizationRequirement> requirements);

    /// <summary>
    /// Checks if a user meets a specific authorization policy
    /// </summary>
    /// <param name="user">The user to check the policy against.</param>
    /// <param name="resource">
    /// An optional resource the policy should be checked with.
    /// If a resource is not required for policy evaluation you may pass null as the value
    /// </param>
    /// <param name="policyName">The name of the policy to check against a specific 
    /// context.</param>
    /// <returns>
    /// A flag indicating whether authorization has succeeded.
    /// Returns a flag indicating whether the user, and optional resource has fulfilled 
    /// the policy.    
    /// <value>true</value> when the policy has been fulfilled; 
    /// otherwise <value>false</value>.
    /// </returns>
    /// <remarks>
    /// Resource is an optional parameter and may be null. Please ensure that you check
    /// it is not null before acting upon it.
    /// </remarks>
    Task<AuthorizationResult> AuthorizeAsync(
                                ClaimsPrincipal user, object resource, string policyName);
}

Yukarıdaki kod, IAuthorizationService'in iki yöntemini vurgular.

IAuthorizationRequirement , yöntemi olmayan bir işaret hizmetidir ve yetkilendirme işleminin başarılı olup olmadığını izlemeye yönelik mekanizmaya yöneliktir.

IAuthorizationHandlerGereksinimlerin karşılanıp karşılanmadığını denetlenmekten her biri sorumludur:

/// <summary>
/// Classes implementing this interface are able to make a decision if authorization
/// is allowed.
/// </summary>
public interface IAuthorizationHandler
{
    /// <summary>
    /// Makes a decision if authorization is allowed.
    /// </summary>
    /// <param name="context">The authorization information.</param>
    Task HandleAsync(AuthorizationHandlerContext context);
}

Bu AuthorizationHandlerContext sınıf, işleyicinin gereksinimlerin karşılanıp karşılanmadığını işaretlemek için kullandığı şeydir:

 context.Succeed(requirement)

Aşağıdaki kod, yetkilendirme hizmetinin Basitleştirilmiş (ve açıklamalar ile açıklamalı) varsayılan uygulamasını gösterir:

public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, 
             object resource, IEnumerable<IAuthorizationRequirement> requirements)
{
    // Create a tracking context from the authorization inputs.
    var authContext = _contextFactory.CreateContext(requirements, user, resource);

    // By default this returns an IEnumerable<IAuthorizationHandlers> from DI.
    var handlers = await _handlers.GetHandlersAsync(authContext);

    // Invoke all handlers.
    foreach (var handler in handlers)
    {
        await handler.HandleAsync(authContext);
    }

    // Check the context, by default success is when all requirements have been met.
    return _evaluator.Evaluate(authContext);
}

Aşağıdaki kod tipik bir göstermektedir ConfigureServices :

public void ConfigureServices(IServiceCollection services)
{
    // Add all of your handlers to DI.
    services.AddSingleton<IAuthorizationHandler, MyHandler1>();
    // MyHandler2, ...

    services.AddSingleton<IAuthorizationHandler, MyHandlerN>();

    // Configure your policies
    services.AddAuthorization(options =>
          options.AddPolicy("Something",
          policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything")));


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

IAuthorizationService [Authorize(Policy = "Something")] Yetkilendirme için veya kullanın.

MVC denetleyicilerine ilke uygulama

RazorSayfalar kullanıyorsanız, bkz. bu belgedeki Razor sayfalara ilke uygulama .

İlkeler, [Authorize] ilke adı ile özniteliği kullanılarak denetleyicilere uygulanır. Örnek:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[Authorize(Policy = "AtLeast21")]
public class AlcoholPurchaseController : Controller
{
    public IActionResult Index() => View();
}

İlkeleri sayfalara uygula Razor

İlkeler, Razor [Authorize] ilke adı ile özniteliği kullanılarak sayfalara uygulanır. Örnek:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;

[Authorize(Policy = "AtLeast21")]
public class AlcoholPurchaseModel : PageModel
{
}

İlkeler Razor sayfa işleyici düzeyinde uygulanamazlar, sayfaya uygulanmaları gerekir.

İlkeler, Razor bir Yetkilendirme kuralıkullanılarak sayfalara uygulanabilir.

Gereksinimler

Yetkilendirme gereksinimi, bir ilkenin geçerli kullanıcı sorumlusunu değerlendirmek için kullanabileceği veri parametreleri koleksiyonudur. "AtLeast21" ilkenizde, gereksinim en düşük yaş olan tek bir parametredir — . Bir gereksinim, boş bir işaret arabirimi olan ıauthorizationrequirement'ı uygular. Parametreli en düşük yaş gereksinimi aşağıdaki gibi uygulanabilir:

using Microsoft.AspNetCore.Authorization;

public class MinimumAgeRequirement : IAuthorizationRequirement
{
    public int MinimumAge { get; }

    public MinimumAgeRequirement(int minimumAge)
    {
        MinimumAge = minimumAge;
    }
}

Yetkilendirme ilkesi birden çok yetkilendirme gereksinimi içeriyorsa, ilke değerlendirmesinin başarılı olması için tüm gereksinimlerin geçmesi gerekir. Diğer bir deyişle, tek bir yetkilendirme ilkesine eklenen birden çok yetkilendirme gereksinimi bir ve temelinde değerlendirilir.

Not

Bir gereksinimin veri veya özellikleri olması gerekmez.

Yetkilendirme işleyicileri

Bir yetkilendirme işleyicisi, bir gereksinimin özelliklerinin değerlendirilmesinden sorumludur. Yetkilendirme işleyicisi, erişim izni verilip verilmediğini belirlemede, gereksinimleri belirtilen Authorizationhandlercontext 'e göre değerlendirir.

Bir gereksinimin birden çok işleyicisiolabilir. Bir işleyici, Authorizationhandler <TRequirement> ' i devralınabilir, burada TRequirement işlenme gereksinimidir. Alternatif olarak, bir işleyici birden fazla gereksinim türünü işlemek için ıauthorizationhandler uygulayabilir.

Bir gereksinim için bir işleyici kullanın

Aşağıda, en az bir yaş işleyicisinin tek bir gereksinimin kullanıldığı bire bir ilişkiye örnek verilmiştir:

using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;

public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   MinimumAgeRequirement requirement)
    {
        if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth &&
                                        c.Issuer == "http://contoso.com"))
        {
            //TODO: 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 && 
                                        c.Issuer == "http://contoso.com").Value);

        int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
        if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
        {
            calculatedAge--;
        }

        if (calculatedAge >= requirement.MinimumAge)
        {
            context.Succeed(requirement);
        }

        //TODO: Use the following if targeting a version of
        //.NET Framework older than 4.6:
        //      return Task.FromResult(0);
        return Task.CompletedTask;
    }
}

Önceki kod, geçerli kullanıcı sorumlusunun bilinen ve güvenilir bir veren tarafından verilen bir Doğum talebi tarihi olup olmadığını belirler. Talep eksik olduğunda yetkilendirme gerçekleşemez, bu durumda tamamlanan bir görev döndürülür. Bir talep bulunduğunda, kullanıcının yaşı hesaplanır. Kullanıcı gereksinim tarafından tanımlanan en düşük yaşı karşılıyorsa, Yetkilendirme başarılı olur. Yetkilendirme başarılı olduğunda, context.Succeed tek parametresi olarak tatmin eden gereksinimle çağrılır.

Birden çok gereksinim için bir işleyici kullanın

Aşağıda, bir izin işleyicisinin üç farklı gereksinim türünü işleyebileceği bir çoktan çoğa ilişkiye örnek verilmiştir:

using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;

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

        //TODO: 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;
    }
}

Yukarıdaki kod, Pendingrequirementsöğesine geçer ve — başarılı olarak işaretlenmemiş gereksinimleri içeren bir özelliktir. Bir ReadPermission gereksinim için, kullanıcı istenen kaynağa erişmek için bir sahip veya sponsor olmalıdır. Veya gereksinimi söz konusu olduğunda EditPermission DeletePermission , istenen kaynağa erişmek için sahip olması gerekir.

İşleyici kaydı

İşleyiciler, yapılandırma sırasında hizmetler koleksiyonuna kaydedilir. Örnek:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddRazorPages();
    services.AddAuthorization(options =>
    {
        options.AddPolicy("AtLeast21", policy =>
            policy.Requirements.Add(new MinimumAgeRequirement(21)));
    });

    services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
}

Yukarıdaki kod, MinimumAgeHandler çağırarak tek bir olarak kaydedilir services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>(); . İşleyiciler, yerleşik hizmet yaşam sürelerininherhangi biri kullanılarak kaydedilebilir.

İşleyici ne döndürmelidir?

Handle İşleyici örnekteki yöntemin değer döndürmediğini unutmayın. Başarı ya da hatanın durumu nasıl belirtilir?

  • Bir işleyici çağırarak başarılı bir context.Succeed(IAuthorizationRequirement requirement) şekilde doğrulanan gereksinimi geçirerek başarılı olduğunu gösterir.

  • Aynı gereksinim için diğer işleyiciler başarılı olabileceğinden, işleyicinin sorunları genellikle işlemesi gerekmez.

  • Diğer gereksinim işleyicileri başarılı olsa bile hatayı güvence altına almak için çağrısı yapın context.Fail .

Bir işleyici veya çağırırsa context.Succeed context.Fail , diğer tüm işleyiciler hala çağırılır. Bu, başka bir işleyicinin bir gereksinimi başarıyla doğrulayan veya başarısız olsa bile, gereksinimlerin günlüğe kaydetme gibi yan etkileri üretmesine olanak tanır. Olarak ayarlandığında false , ınvokehandlersafterfailure özelliği, çağrıldığında işleyicilerin yürütülmesi kısa devre dışı context.Fail olur. InvokeHandlersAfterFailure Varsayılan olarak true , bu durumda tüm işleyiciler çağrılır.

Not

Yetkilendirme işleyicileri, kimlik doğrulama başarısız olsa bile çağrılır.

Bir gereksinim için neden birden çok işleyici istiyorum?

Değerlendirmenin bir veya temelinde olmasını istediğiniz durumlarda, tek bir gereksinim için birden çok işleyici uygulayın. Örneğin, Microsoft yalnızca ana kartlarla açık olan kapılara sahiptir. Ana kartınızı evden bırakırsanız, alıcı geçici bir etiket yazdırır ve kapıyı sizin için açar. Bu senaryoda, tek bir gereksinimi incelerken tek bir gereksinimin, Buildingentry, ancak birden çok işleyici vardır.

BuildingEntryRequirement. cs

using Microsoft.AspNetCore.Authorization;

public class BuildingEntryRequirement : IAuthorizationRequirement
{
}

BadgeEntryHandler. cs

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;

public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                   BuildingEntryRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "BadgeId" &&
                                       c.Issuer == "http://microsoftsecurity"))
        {
            context.Succeed(requirement);
        }

        //TODO: 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.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using PoliciesAuthApp1.Services.Requirements;

public class TemporaryStickerHandler : AuthorizationHandler<BuildingEntryRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, 
                                                   BuildingEntryRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "TemporaryBadgeId" &&
                                       c.Issuer == "https://microsoftsecurity"))
        {
            // We'd also check the expiration date on the sticker.
            context.Succeed(requirement);
        }

        //TODO: Use the following if targeting a version of
        //.NET Framework older than 4.6:
        //      return Task.FromResult(0);
        return Task.CompletedTask;
    }
}

Her iki işleyicinin de kaydedildiğindenemin olun. Bir ilke değerlendirirken her iki işleyici de başarılı olursa BuildingEntryRequirement , ilke değerlendirmesi başarılı olur.

Bir ilkeyi yerine getirmek için bir Func kullanın

Kodun kodda hızlı bir şekilde kullanılması için bir ilkeyi karşıladığı durumlar olabilir. İlke Func<AuthorizationHandlerContext, bool> Oluşturucu ile ilkenizi yapılandırırken bir sağlamak mümkündür RequireAssertion .

Örneğin, önceki, BadgeEntryHandler aşağıdaki gibi yeniden yazılabilir:

services.AddAuthorization(options =>
{
     options.AddPolicy("BadgeEntry", policy =>
        policy.RequireAssertion(context =>
            context.User.HasClaim(c =>
                (c.Type == "BadgeId" ||
                 c.Type == "TemporaryBadgeId") &&
                 c.Issuer == "https://microsoftsecurity")));
});

İşleyicilerde MVC istek bağlamına erişme

HandleRequirementAsyncBir yetkilendirme işleyicisinde uyguladığınız yöntemin iki parametresi vardır: bir AuthorizationHandlerContext ve TRequirement işleme çalışıyorsunuz. Daha SignalR Resource AuthorizationHandlerContext fazla bilgi GEÇIRMEK için, MVC gibi çerçeveler veya üzerinde özelliğine herhangi bir nesne eklemek ücretsizdir.

Endpoint Routing kullanılırken, yetkilendirme genellikle yetkilendirme ara yazılımı tarafından işlenir. Bu durumda, Resource özelliği öğesinin bir örneğidir Endpoint . Uç noktası, yönlendirolduğunuz temel kaynağı yoklayabilmeniz için kullanılabilir. Örnek:

if (context.Resource is Endpoint endpoint)
{
   var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
   ...
}

Uç nokta geçerli bir erişim sağlamaz HttpContext . Endpoint Routing kullanılırken, IHttpContextAcessor HttpContext bir yetkilendirme işleyicisinin içine erişmek için kullanın. Daha fazla bilgi için bkz. özel bileşenlerden HttpContext kullanma.

Geleneksel yönlendirme ile veya MVC 'nin yetkilendirme filtresinin bir parçası olarak yetkilendirme gerçekleştiğinde, değeri Resource bir AuthorizationFilterContext örnek olur. Bu özellik HttpContext ,, ve IÇIN RouteData MVC ve sayfalar tarafından sağlanan diğer her şeye erişim sağlar Razor .

Özelliğin kullanımı Framework 'e Resource özgüdür. Özelliğindeki bilgilerin kullanılması, Resource Yetkilendirme ilkelerinizi belirli çerçeveler ile sınırlandırır. ResourceAnahtar sözcüğünü kullanarak özelliği atamalısınız is ve sonra, kodunuzun InvalidCastException diğer çerçeveler üzerinde çalıştırıldığında bir ile çökmemesini sağlamak için dönüştürmenin başarılı olduğunu doğrulayın:

// Requires the following import:
//     using Microsoft.AspNetCore.Mvc.Filters;
if (context.Resource is AuthorizationFilterContext mvcContext)
{
    // Examine MVC-specific things like routing data.
}

Genel olarak tüm kullanıcıların kimliğinin doğrulanmasını gerektir

Tüm kullanıcıların kimliklerinin nasıl doğrulandığını öğrenmek için bkz. kimliği doğrulanmış kullanıcılar gerektirme.