Пользовательские политики авторизации с IAuthorizationRequirementData
Статья
В этой статье
Рассмотрим следующий пример, реализующий настраиваемый MinimumAgeAuthorizationHandler:
using AuthRequirementsData.Authorization;
using Microsoft.AspNetCore.Authorization;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();
builder.Services.AddControllers();
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeAuthorizationHandler>();
var app = builder.Build();
app.MapControllers();
app.Run();
Класс MinimumAgeAuthorizationHandler:
using Microsoft.AspNetCore.Authorization;
using System.Globalization;
using System.Security.Claims;
namespace AuthRequirementsData.Authorization;
class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeAuthorizeAttribute>
{
private readonly ILogger<MinimumAgeAuthorizationHandler> _logger;
public MinimumAgeAuthorizationHandler(ILogger<MinimumAgeAuthorizationHandler> logger)
{
_logger = logger;
}
// Check whether a given MinimumAgeRequirement is satisfied or not for a particular
// context.
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
MinimumAgeAuthorizeAttribute requirement)
{
// Log as a warning so that it's very clear in sample output which authorization
// policies(and requirements/handlers) are in use.
_logger.LogWarning("Evaluating authorization requirement for age >= {age}",
requirement.Age);
// Check the user's age.
var dateOfBirthClaim = context.User.FindFirst(c => c.Type ==
ClaimTypes.DateOfBirth);
if (dateOfBirthClaim != null)
{
// If the user has a date of birth claim, check their age.
var dateOfBirth = Convert.ToDateTime(dateOfBirthClaim.Value,
CultureInfo.InvariantCulture);
var age = DateTime.Now.Year - dateOfBirth.Year;
if (dateOfBirth > DateTime.Now.AddYears(-age))
{
// Adjust age if the user hasn't had a birthday yet this year.
age--;
}
// If the user meets the age criterion, mark the authorization requirement
// succeeded.
if (age >= requirement.Age)
{
_logger.LogInformation(
"Minimum age authorization requirement {age} satisfied",
requirement.Age);
context.Succeed(requirement);
}
else
{
_logger.LogInformation("Current user's DateOfBirth claim ({dateOfBirth})"
+ " does not satisfy the minimum age authorization requirement {age}",
dateOfBirthClaim.Value,
requirement.Age);
}
}
else
{
_logger.LogInformation("No DateOfBirth claim present");
}
return Task.CompletedTask;
}
}
Настраиваемый MinimumAgePolicyProvider:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
namespace AuthRequirementsData.Authorization;
class MinimumAgePolicyProvider : IAuthorizationPolicyProvider
{
const string POLICY_PREFIX = "MinimumAge";
public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }
public MinimumAgePolicyProvider(IOptions<AuthorizationOptions> options)
{
FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}
public Task<AuthorizationPolicy> GetDefaultPolicyAsync() =>
FallbackPolicyProvider.GetDefaultPolicyAsync();
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync() =>
FallbackPolicyProvider.GetFallbackPolicyAsync();
public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase) &&
int.TryParse(policyName.Substring(POLICY_PREFIX.Length), out var age))
{
var policy = new AuthorizationPolicyBuilder(
JwtBearerDefaults.AuthenticationScheme);
policy.AddRequirements(new MinimumAgeRequirement(age));
return Task.FromResult<AuthorizationPolicy?>(policy.Build());
}
return Task.FromResult<AuthorizationPolicy?>(null);
}
}
ASP.NET Core использует только один поставщик политики авторизации. Если пользовательская реализация не обрабатывает все политики, включая политики по умолчанию и т. д., он должен вернуться к альтернативному поставщику. В предыдущем примере поставщик политики авторизации по умолчанию:
Создано с параметрами из контейнера внедрения зависимостей.
Используется, если этот пользовательский поставщик не может обрабатывать заданное имя политики.
Если поставщик настраиваемых политик может обрабатывать все ожидаемые имена политик, установка резервной политики GetFallbackPolicyAsync() не требуется.
class MinimumAgePolicyProvider : IAuthorizationPolicyProvider
{
const string POLICY_PREFIX = "MinimumAge";
public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }
public MinimumAgePolicyProvider(IOptions<AuthorizationOptions> options)
{
FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}
public Task<AuthorizationPolicy> GetDefaultPolicyAsync() =>
FallbackPolicyProvider.GetDefaultPolicyAsync();
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync() =>
FallbackPolicyProvider.GetFallbackPolicyAsync();
Политики ищутся по имени строки, поэтому параметры, например, ageвстраиваются в имена политик. Это абстрагируется от разработчиков более строго типизированными атрибутами, производными от AuthorizeAttribute. Например, [MinimumAgeAuthorize()] атрибут в этом примере ищет политики по имени строки.
public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase) &&
int.TryParse(policyName.Substring(POLICY_PREFIX.Length), out var age))
{
var policy = new AuthorizationPolicyBuilder(
JwtBearerDefaults.AuthenticationScheme);
policy.AddRequirements(new MinimumAgeRequirement(age));
return Task.FromResult<AuthorizationPolicy?>(policy.Build());
}
return Task.FromResult<AuthorizationPolicy?>(null);
}
IAuthorizationRequirementData Использует MinimumAgeAuthorizeAttribute интерфейс, позволяющий определению атрибута указать требования, связанные с политикой авторизации:
using Microsoft.AspNetCore.Authorization;
namespace AuthRequirementsData.Authorization;
class MinimumAgeAuthorizeAttribute : AuthorizeAttribute, IAuthorizationRequirement,
IAuthorizationRequirementData
{
public MinimumAgeAuthorizeAttribute(int age) => Age = age;
public int Age { get; }
public IEnumerable<IAuthorizationRequirement> GetRequirements()
{
yield return this;
}
}
Отображается GreetingsController имя пользователя при удовлетворении минимальной политики возраста:
using AuthRequirementsData.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace AuthRequirementsData.Controllers;
[ApiController]
[Route("api/[controller]")]
public class GreetingsController : Controller
{
[MinimumAgeAuthorize(16)]
[HttpGet("hello")]
public string Hello() => $"Hello {(HttpContext.User.Identity?.Name ?? "world")}!";
}
curl -i -H "Authorization: Bearer <token from dotnet user-jwts>" http://localhost:<port>/api/greetings/hello
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.
Отзыв о ASP.NET Core
ASP.NET Core — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв:
Продемонстрировать функции идентификатора Microsoft Entra для модернизации решений удостоверений, реализации гибридных решений и реализации управления удостоверениями.
Узнайте, как использовать пользовательский интерфейс IAuthorizationPolicyProvider в приложении ASP.NET Core для динамического создания политик авторизации.