ASP.NET Core'da ilke tabanlı yetkilendirme
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ı 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 gereksinimden 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)));
});
Yukarıdaki örnekte bir "AtLeast21" ilkesi oluşturulur. Tek bir gereksinimi vardır; minimum yaş, gereksinime parametre olarak sağlanır.
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çi hizmetidir ve yetkilendirmenin başarılı olup olmadığını izlemeye yönelik mekanizmadır.
Her IAuthorizationHandler biri gereksinimlerin karşılandığından 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);
}
AuthorizationHandlerContext sınıfı, işleyicinin gereksinimlerin karşılanıp karşılanmadığını işaretlemek için kullandığı sınıftır:
context.Succeed(requirement)
Aşağıdaki kod, yetkilendirme hizmetinin basitleştirilmiş (ve açıklamalarla ek 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<IAuthorizationHandler> 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 için , [Authorize(Policy = "Something")]
veya RequireAuthorization("Something")
kullanınIAuthorizationService.
MVC denetleyicilerine ilke uygulama
Sayfaları kullanan Razor uygulamalar için İlkeleri Sayfalara Razor uygulama bölümüne bakın.
İlke adıyla özniteliğini [Authorize]
kullanarak denetleyicilere ilkeler uygulayın:
[Authorize(Policy = "AtLeast21")]
public class AtLeast21Controller : Controller
{
public IActionResult Index() => View();
}
Denetleyici ve eylem düzeylerinde birden çok ilke uygulanırsa, erişim verilmeden önce tüm ilkelerin geçmesi gerekir:
[Authorize(Policy = "AtLeast21")]
public class AtLeast21Controller2 : Controller
{
[Authorize(Policy = "IdentificationValidated")]
public IActionResult Index() => View();
}
Sayfalara Razor ilke uygulama
İlke adıyla özniteliğini [Authorize]
kullanarak Sayfalar'a Razor ilkeler uygulayın. Örneğin:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace AuthorizationPoliciesSample.Pages;
[Authorize(Policy = "AtLeast21")]
public class AtLeast21Model : PageModel { }
İlkeler Sayfa işleyici düzeyinde uygulanamıyorRazor, Sayfaya uygulanmalıdır.
İlkeler, yetkilendirme kuralı kullanılarak Sayfalar'a Razor da uygulanabilir.
Uç noktalara ilke uygulama
İlke adıyla kullanarak RequireAuthorization uç noktalara ilkeler uygulayın. Örneğin:
app.MapGet("/helloworld", () => "Hello World!")
.RequireAuthorization("AtLeast21");
Gereksinimler
Yetkilendirme gereksinimi, bir ilkenin geçerli kullanıcı sorumlusunu değerlendirmek için kullanabileceği veri parametreleri koleksiyonudur. "AtLeast21" ilkemizde gereksinim tek bir parametredir( en düşük yaş). Bir gereksinim, boş bir işaretçi arabirimi olan öğesini uygular IAuthorizationRequirement. Parametreli minimum yaş gereksinimi aşağıdaki gibi uygulanabilir:
using Microsoft.AspNetCore.Authorization;
namespace AuthorizationPoliciesSample.Policies.Requirements;
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public MinimumAgeRequirement(int minimumAge) =>
MinimumAge = minimumAge;
public int MinimumAge { get; }
}
Yetkilendirme ilkesi birden çok yetkilendirme gereksinimi 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 gereksinimi VE temelinde ele alınır.
Not
Bir gereksinimin veri veya özelliklere sahip olması gerekmez.
Yetkilendirme işleyicileri
Yetkilendirme işleyicisi, bir gereksinimin özelliklerinin değerlendirilmesinden sorumludur. Yetkilendirme işleyicisi, erişime izin verilip verilmediğini belirlemek için sağlanana AuthorizationHandlerContext göre gereksinimleri değerlendirir.
Bir gereksinim birden çok işleyiciye sahip olabilir. İşleyici devralabilir AuthorizationHandler<TRequirement>, burada TRequirement
işlenmesi gereken bir gereksinimdir. Alternatif olarak, bir işleyici birden fazla gereksinim türünü işlemek için doğrudan uygulayabilir IAuthorizationHandler .
Bir gereksinim için işleyici kullanma
Aşağıdaki örnekte, en düşük yaş işleyicisinin tek bir gereksinimi işlediği bire bir ilişki gösterilmektedir:
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ı sorumlusunun bilinen ve güvenilen bir Veren tarafından verilmiş bir doğum talebi tarihi olup olmadığını belirler. Talep eksik olduğunda yetkilendirme gerçekleşemez ve bu durumda tamamlanmış bir görev döndürülür. Talep mevcut olduğ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ı kabul edilir. Yetkilendirme başarılı olduğunda, context.Succeed
tek parametresi olarak karşılanan gereksinimle çağrılır.
Birden çok gereksinim için işleyici kullanma
Aşağıdaki örnekte, bir izin işleyicisinin üç farklı gereksinim türünü işleyebildiği bire çok ilişkisi gösterilmektedir:
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 geçiş yaparak PendingRequirementsgereksinimleri içeren ve başarılı olarak işaretlenmemiş bir özelliktir. ReadPermission
Bir gereksinim için kullanıcının istenen kaynağa erişmek için sahip veya sponsor olması gerekir. EditPermission
veya DeletePermission
gereksinimi için, istenen kaynağa erişmek için sahip olmaları gerekir.
İşleyici kaydı
Yapılandırma sırasında hizmet koleksiyonuna işleyicileri kaydedin. Örneğin:
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
Önceki kod tekil olarak kaydeder MinimumAgeHandler
. İşleyiciler yerleşik hizmet ömründen herhangi biri kullanılarak kaydedilebilir.
Hem gereksinimi hem de işleyiciyi hem hem de IAuthorizationRequirement IAuthorizationHandleruygulayan tek bir sınıfa paketlemek mümkündür. Bu paketleme işleyici ile gereksinim arasında sıkı bir bağlantı 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 gereksinimini ortadan kaldırır.
Öğesinin hem bir gereksinim hem de tam olarak kendi içinde yer alan bir sınıfta işleyici olduğu AssertionRequirement
iyi bir örnek için AssertionRequirement sınıfına bakın.
bir işleyici ne döndürmelidir?
İşleyici örneğindeki yönteminin değer döndürmediğini Handle
unutmayın. Başarı veya başarısızlık durumu nasıl belirtilir?
İşleyici, başarıyla doğrulanmış gereksinimi geçirerek öğesini çağırarak
context.Succeed(IAuthorizationRequirement requirement)
başarıyı gösterir.Aynı gereksinime yönelik diğer işleyiciler başarılı olabileceğinden, işleyicinin hataları genel olarak işlemesi gerekmez.
Başarısızlığı garanti etmek için, diğer gereksinim işleyicileri başarılı olsa bile öğesini çağırın
context.Fail
.
bir işleyici veya context.Fail
çağırırsacontext.Succeed
, diğer tüm işleyiciler hala çağrılır. Bu, başka bir işleyici bir gereksinimi başarıyla doğrulasa veya başarısız olsa bile gerçekleşen günlüğe kaydetme gibi yan etkiler üretmeye olanak tanır. olarak false
InvokeHandlersAfterFailure ayarlandığında, özelliği çağrıldığında context.Fail
işleyicilerin yürütülmesini kısa devreler. InvokeHandlersAfterFailure
varsayılan değeridir true
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. Ayrıca işleyiciler herhangi bir sırada yürütülebilir, bu nedenle belirli bir sırada çağrılmalarına bağımlı değildir.
Neden bir gereksinim için birden çok işleyici isteyebilirim?
Değerlendirmenin VEYA temelinde olmasını istediğiniz durumlarda, tek bir gereksinim için birden çok işleyici uygulayın. Örneğin, Microsoft'un yalnızca anahtar kartlarıyla açılan kapıları vardır. Anahtar kartınızı adresinde homebırakırsanız resepsiyonist geçici bir çıkartma yazdırır ve kapıyı sizin için açar. Bu senaryoda, tek bir gereksiniminiz (BuildingEntry) ancak her biri tek bir gereksinimi inceleyerek birden çok işleyiciye sahip olursunuz.
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ğerini değerlendirdiğinde işleyicilerden BuildingEntryRequirement
biri başarılı olursa, ilke değerlendirmesi başarılı olur.
İlkeyi yerine getirmek için func kullanma
bir ilkeyi yerine getirmenin kodla ifade edilmesi kolay olduğu durumlar olabilir. İlke Func<AuthorizationHandlerContext, bool>
oluşturucusu ile RequireAssertion
bir ilke yapılandırırken sağlamak mümkündür.
Örneğin, önceki BadgeEntryHandler
aşağıdaki 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 isteği bağlamı erişimi
yöntemi iki HandleRequirementAsync
parametreye sahiptir: an AuthorizationHandlerContext
ve TRequirement
işleniyor. MVC gibi çerçeveler veya SignalR ek bilgi geçirmek için Resource
üzerinde AuthorizationHandlerContext
özelliğine herhangi bir nesne eklemek ücretsizdir.
Uç nokta yönlendirme kullanılırken yetkilendirme genellikle Yetkilendirme Ara Yazılımı tarafından işlenir. Bu durumda özelliği Resource
bir örneğidir HttpContext. Bağlam geçerli uç noktaya erişmek için kullanılabilir ve bu da yönlendirme yaptığınız temel kaynağı araştırmak için kullanılabilir. Örneğin:
if (context.Resource is HttpContext httpContext)
{
var endpoint = httpContext.GetEndpoint();
var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
...
}
Geleneksel yönlendirmede veya MVC yetkilendirme filtresinin bir parçası olarak yetkilendirme gerçekleştiğinde değeri Resource
bir AuthorizationFilterContext örnektir. Bu özellik, , RouteData
ve MVC ve Razor Pages tarafından sağlanan diğer her şeye erişim HttpContext
sağlar.
özelliğinin kullanımı çerçeveye Resource
özgüdür. özelliğindeki Resource
bilgileri kullanmak yetkilendirme ilkelerinizi belirli çerçevelerle sınırlar. anahtar sözcüğünü kullanarak özelliğini yayınlayın Resource
is
ve ardından diğer çerçevelerde çalıştırıldığında kodunuzun bir InvalidCastException
ile kilitlenmediğinden emin olmak için atamanın başarılı olduğunu onaylayı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ı gerekir
Genel olarak tüm kullanıcıların kimliğinin doğrulanmış olmasını gerektirme hakkında bilgi için bkz . Kimliği doğrulanmış kullanıcılar gerektirme.
Dış hizmet örneğiyle yetkilendirme
AspNetCore.Docs.Samples üzerindeki örnek kod, bir dış yetkilendirme hizmetiyle ek yetkilendirme gereksinimlerini nasıl uygulayacaklarını gösterir. Örnek Contoso.API
projenin güvenliği Azure AD ile sağlanır. Projeden yapılan ek yetkilendirme denetimi, istemci uygulamasının Contoso.Security.API
Contoso.API
API'yi çağırıp çağıramayacağını GetWeather
açıklayan bir yük döndürür.
Örneği yapılandırma
Microsoft Entra Id kiracınızda bir uygulama kaydı oluşturun:
Bir AppRole atayın.
API izinleri'nin altında AppRole'ı izin olarak ekleyin ve Yönetici onayı verin. Bu kurulumda, bu uygulama kaydının hem API'yi hem de API'yi çağıran istemciyi temsil ettiğini unutmayın. İsterseniz iki uygulama kaydı oluşturabilirsiniz. Bu kurulumu kullanıyorsanız, yalnızca API izinlerini gerçekleştirdiğinizden emin olun, appRole'u yalnızca istemci için izin adımı olarak ekleyin. Yalnızca istemci uygulama kaydı için bir istemci gizli dizisi oluşturulması gerekir.
Contoso.API
Projeyi aşağıdaki ayarlarla yapılandırın:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<Tenant name from AAD properties>.onmicrosoft.com",
"TenantId": "<Tenant Id from AAD properties>",
"ClientId": "<Client Id from App Registration representing the API>"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
- Aşağıdaki ayarlarla yapılandırın
Contoso.Security.API
:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"AllowedClients": [
"<Use the appropriate Client Id representing the Client calling the API>"
]
}
ContosoAPI.collection.json dosyasını açın ve aşağıdakilerle bir ortam yapılandırın:
ClientId
: API'yi çağıran istemciyi temsil eden uygulama kaydından istemci kimliği.clientSecret
: API'yi çağıran istemciyi temsil eden uygulama kaydından İstemci Gizli Dizisi.TenantId
: AAD özelliklerinden kiracı kimliği
Dosyadan
ContosoAPI.collection.json
komutları ayıklayın ve uygulamayı test etmek için cURL komutları oluşturmak için kullanın.Çözümü çalıştırın ve API'yi çağırmak için cURL kullanın. öğesine
Contoso.Security.API.SecurityPolicyController
kesme noktaları ekleyebilir ve hava durumunu alma izninin verilip verilmeyeceğini onaylamada kullanılan istemci kimliğinin geçirildiğini gözlemleyebilirsiniz.
Ek kaynaklar
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ı 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 gereksinimden oluşur. Aşağıdaki yöntemde yetkilendirme hizmeti yapılandırmasının Startup.ConfigureServices
bir parçası olarak 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. Tek bir gereksinimi vardır; minimum yaş, gereksinime parametre olarak sağlanır.
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çi hizmetidir ve yetkilendirmenin başarılı olup olmadığını izlemeye yönelik mekanizmadır.
Her IAuthorizationHandler biri gereksinimlerin karşılandığından 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);
}
AuthorizationHandlerContext sınıfı, işleyicinin gereksinimlerin karşılanıp karşılanmadığını işaretlemek için kullandığı sınıftır:
context.Succeed(requirement)
Aşağıdaki kod, yetkilendirme hizmetinin basitleştirilmiş (ve açıklamalarla ek 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 ConfigureServices
bir 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 için veya [Authorize(Policy = "Something")]
kullanınIAuthorizationService.
MVC denetleyicisine ilke uygulama
Pages kullanıyorsanızRazor, bu belgedeki Sayfalara ilke uygulama konusuna Razor bakın.
İlkeler, ilke adıyla özniteliği kullanılarak [Authorize]
denetleyicilere uygulanır. Örneğin:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[Authorize(Policy = "AtLeast21")]
public class AlcoholPurchaseController : Controller
{
public IActionResult Index() => View();
}
Sayfalara Razor ilke uygulama
İlkeler, ilke adıyla özniteliği kullanılarak [Authorize]
Sayfalar'a Razor uygulanır. Örneğin:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
[Authorize(Policy = "AtLeast21")]
public class AlcoholPurchaseModel : PageModel
{
}
İlkeler Sayfa işleyici düzeyinde uygulanamıyorRazor, Sayfaya uygulanmalıdır.
İlkeler, yetkilendirme kuralı kullanılarak Sayfalar'a Razor uygulanabilir.
Gereksinimler
Yetkilendirme gereksinimi, bir ilkenin geçerli kullanıcı sorumlusunu değerlendirmek için kullanabileceği veri parametreleri koleksiyonudur. "AtLeast21" ilkemizde gereksinim tek bir parametredir( en düşük yaş). Bir gereksinim, boş bir işaretçi arabirimi olan öğesini uygular IAuthorizationRequirement. Parametreli minimum 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. Başka bir deyişle, tek bir yetkilendirme ilkesine eklenen birden çok yetkilendirme gereksinimi VE temelinde ele alınır.
Not
Bir gereksinimin veri veya özelliklere sahip olması gerekmez.
Yetkilendirme işleyicileri
Yetkilendirme işleyicisi, bir gereksinimin özelliklerinin değerlendirilmesinden sorumludur. Yetkilendirme işleyicisi, erişime izin verilip verilmediğini belirlemek için sağlanana AuthorizationHandlerContext göre gereksinimleri değerlendirir.
Bir gereksinim birden çok işleyiciye sahip olabilir. İşleyici devralabilir AuthorizationHandler<TRequirement>, burada TRequirement
işlenmesi gereken bir gereksinimdir. Alternatif olarak, bir işleyici birden fazla gereksinim türünü işlemek için uygulayabilir IAuthorizationHandler .
Bir gereksinim için işleyici kullanma
Aşağıdaki örnekte, en düşük yaş işleyicisinin tek bir gereksinimi kullandığı bire bir ilişki gösterilmektedir:
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ı sorumlusunun bilinen ve güvenilen bir Veren tarafından verilmiş bir doğum talebi tarihi olup olmadığını belirler. Talep eksik olduğunda yetkilendirme gerçekleşemez ve bu durumda tamamlanmış bir görev döndürülür. Talep mevcut olduğ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ı kabul edilir. Yetkilendirme başarılı olduğunda, context.Succeed
tek parametresi olarak karşılanan gereksinimle çağrılır.
Birden çok gereksinim için işleyici kullanma
Aşağıdaki örnekte, bir izin işleyicisinin üç farklı gereksinim türünü işleyebildiği bire çok ilişkisi gösterilmektedir:
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 geçiş yaparak PendingRequirementsgereksinimleri içeren ve başarılı olarak işaretlenmemiş bir özelliktir. ReadPermission
Bir gereksinim için kullanıcının istenen kaynağa erişmek için sahip veya sponsor olması gerekir. EditPermission
Veya DeletePermission
gereksinimi için kullanıcının istenen kaynağa erişebilmesi için sahip olması gerekir.
İşleyici kaydı
İşleyiciler yapılandırma sırasında hizmet koleksiyonuna kaydedilir. Örneğin:
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, çağırarak services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
tekil olarak kaydederMinimumAgeHandler
. İşleyiciler yerleşik hizmet ömründen herhangi biri kullanılarak kaydedilebilir.
Hem gereksinimi hem de işleyiciyi hem de IAuthorizationRequirement IAuthorizationHandleruygulayan tek bir sınıfta paketlemek mümkündür. Bu paketleme işleyici ile gereksinim arasında sıkı bir bağlantı 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 gereksinimini ortadan kaldırır.
Öğesinin hem bir gereksinim hem de tam olarak kendi içinde yer alan bir sınıfta işleyici olduğu AssertionRequirement
iyi bir örnek için AssertionRequirement sınıfına bakın.
bir işleyici ne döndürmelidir?
İşleyici örneğindeki yönteminin değer döndürmediğini Handle
unutmayın. Başarı veya başarısızlık durumu nasıl belirtilir?
İşleyici, başarıyla doğrulanmış gereksinimi geçirerek öğesini çağırarak
context.Succeed(IAuthorizationRequirement requirement)
başarıyı gösterir.Aynı gereksinime yönelik diğer işleyiciler başarılı olabileceğinden, işleyicinin hataları genel olarak işlemesi gerekmez.
Başarısızlığı garanti etmek için, diğer gereksinim işleyicileri başarılı olsa bile öğesini çağırın
context.Fail
.
bir işleyici veya context.Fail
çağırırsacontext.Succeed
, diğer tüm işleyiciler hala çağrılır. Bu, başka bir işleyici bir gereksinimi başarıyla doğrulasa veya başarısız olsa bile gerçekleşen günlüğe kaydetme gibi yan etkiler üretmeye olanak tanır. olarak false
InvokeHandlersAfterFailure ayarlandığında, özelliği çağrıldığında context.Fail
işleyicilerin yürütülmesini kısa devreler. InvokeHandlersAfterFailure
varsayılan değeridir true
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.
Neden bir gereksinim için birden çok işleyici isteyebilirim?
Değerlendirmenin VEYA temelinde olmasını istediğiniz durumlarda, tek bir gereksinim için birden çok işleyici uygulayın. Örneğin, Microsoft'un yalnızca anahtar kartlarıyla açılan kapıları vardır. Anahtar kartınızı adresinde homebırakırsanız resepsiyonist geçici bir çıkartma yazdırır ve kapıyı sizin için açar. Bu senaryoda, tek bir gereksiniminiz (BuildingEntry) ancak her biri tek bir gereksinimi inceleyerek birden çok işleyiciye sahip olursunuz.
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ğerini değerlendirdiğinde işleyicilerden BuildingEntryRequirement
biri başarılı olursa, ilke değerlendirmesi başarılı olur.
İlkeyi yerine getirmek için func kullanma
bir ilkeyi yerine getirmenin kodla ifade edilmesi kolay olduğu durumlar olabilir. İlke oluşturucu ile RequireAssertion
ilkenizi yapılandırırken bir Func<AuthorizationHandlerContext, bool>
sağlamak mümkündür.
Ö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 isteği bağlamı erişimi
Yetkilendirme HandleRequirementAsync
işleyicisinde uyguladığınız yöntemin iki parametresi vardır: an AuthorizationHandlerContext
ve işlemekte TRequirement
olduğunuz. MVC gibi çerçeveler veya SignalR ek bilgi geçirmek için Resource
üzerinde AuthorizationHandlerContext
özelliğine herhangi bir nesne eklemek ücretsizdir.
Uç nokta yönlendirme kullanılırken yetkilendirme genellikle Yetkilendirme Ara Yazılımı tarafından işlenir. Bu durumda özelliği Resource
bir örneğidir HttpContext. Bağlam geçerli uç noktaya erişmek için kullanılabilir ve bu da yönlendirme yaptığınız temel kaynağı araştırmak için kullanılabilir. Örneğin:
if (context.Resource is HttpContext httpContext)
{
var endpoint = httpContext.GetEndpoint();
var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
...
}
Geleneksel yönlendirmede veya MVC yetkilendirme filtresinin bir parçası olarak yetkilendirme gerçekleştiğinde değeri Resource
bir AuthorizationFilterContext örnektir. Bu özellik, , RouteData
ve MVC ve Razor Pages tarafından sağlanan diğer her şeye erişim HttpContext
sağlar.
özelliğinin kullanımı çerçeveye Resource
özgüdür. özelliğindeki Resource
bilgileri kullanmak yetkilendirme ilkelerinizi belirli çerçevelerle sınırlar. anahtar sözcüğünü kullanarak özelliğini yayınlayın Resource
is
ve ardından diğer çerçevelerde çalıştırıldığında kodunuzun bir InvalidCastException
ile kilitlenmediğinden emin olmak için atamanın başarılı olduğunu onaylayı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ı gerekir
Genel olarak tüm kullanıcıların kimliğinin doğrulanmış olmasını gerektirme hakkında bilgi için bkz . Kimliği doğrulanmış kullanıcılar gerektirme.
ASP.NET Core