Skip to content

Instantly share code, notes, and snippets.

@Platonenkov
Last active May 14, 2021 09:06
Show Gist options
  • Save Platonenkov/598ebdaa73bebf81fc8d4f66c87fc226 to your computer and use it in GitHub Desktop.
Save Platonenkov/598ebdaa73bebf81fc8d4f66c87fc226 to your computer and use it in GitHub Desktop.
Policy for authorization
public class CustomAuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider
{
private readonly AuthorizationOptions _Options;
public CustomAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options) : base(options) { _Options = options.Value; }
#region Overrides of DefaultAuthorizationPolicyProvider
public override async Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
{
var policy_exist = await base.GetPolicyAsync(policyName);
if (policy_exist == null)
{
if(policyName == "OlderThan18")
{
policy_exist = new AuthorizationPolicyBuilder().AddRequirements(new OlderThanRequirement(18)).Build();
_Options.AddPolicy(policyName, policy_exist);
}
if(policyName == "ApiPolicy")
{
policy_exist = new AuthorizationPolicyBuilder().RequireClaim("Scope", "api1").Build();
_Options.AddPolicy(policyName, policy_exist);
}
}
return policy_exist;
}
#endregion
}
public class OlderThanRequirement : IAuthorizationRequirement
{
public OlderThanRequirement(int years)
{
Years = years;
}
public int Years { get; }
}
public class OlderThanRequirementHandler : AuthorizationHandler<OlderThanRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, OlderThanRequirement requirement)
{
var hasClaim = context.User.HasClaim(x => x.Type == ClaimTypes.DateOfBirth);
if (!hasClaim)
{
return Task.CompletedTask;
}
var dateOfBirth = context.User.FindFirst(x => x.Type == ClaimTypes.DateOfBirth)?.Value;
if(dateOfBirth is null)
return Task.CompletedTask;
if (!DateTime.TryParse(dateOfBirth, new CultureInfo("ru-RU"), DateTimeStyles.None, out var date))
return Task.CompletedTask;
var canEnterDiff = DateTime.Now.Year - date.Year;
if (canEnterDiff >= requirement.Years)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public void ConfigureServices(IServiceCollection services)
{
//services.AddAuthorization(options=>
//{
//options.AddPolicy("OlderThan18", policy=>
//{
//policy.AddRequirements(new OlderThanRequirement(18));
//});
//}
services.AddAuthorization();
services.AddSingleton<IAuthorizationHandler, OlderThanRequirementHandler>();
services.AddSingleton<IAuthorizationPolicyProvider, CustomAuthorizationPolicyProvider>();
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.AccessTokenValidation;
using Microsoft.AspNetCore.Authorization;
namespace ApiSample1.Controllers
{
[ApiController]
[Route("[controller]")]
[Authorize(Policy = "OlderThan18")]
public class WeatherForecastController : ControllerBase
{
//code
}
}
@Platonenkov
Copy link
Author

по этапам:

  1. создаём модель требования (OlderThanRequirement.cs)
  2. создаём обработчик требования (OlderThanRequirementHandler.cs)
  3. создаём провайдер который будет регистрировать политики (CustomAuthorizationPolicyProvider.cs)
  4. регистрируем сервисы в Startup.cs
  5. добавляем атрибут авторизации в контроллере ([Authorize(Policy = "OlderThan18")] ) как у меня в WeatherForecastController.cs

Если вдруг api отвечает что-то подобное

Authorization failed. These requirements were not met: ApiSample1.Startup+OlderThanRequirement AuthenticationScheme: Bearer was forbidden.

значит вы неправильно зарегистрировали сервисы и сервер просто не видит политику для проверки требования

не забыть добавить в ApiResources: Scopes и Claims если требования стоят на них

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment