Skip to content

Instantly share code, notes, and snippets.

@conwid
Created May 16, 2023 16:46
Show Gist options
  • Save conwid/c465eabde535c0acdf90b1ff9e5a1fb0 to your computer and use it in GitHub Desktop.
Save conwid/c465eabde535c0acdf90b1ff9e5a1fb0 to your computer and use it in GitHub Desktop.
The second demo shows how to extend authorization using the custom user info.
public class CustomClaimFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
public CustomClaimFactory(UserManager<ApplicationUser> userManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, optionsAccessor)
{
}
protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
{
var claims = await base.GenerateClaimsAsync(user);
claims.AddClaim(new Claim("http://schemas.techeddemo.com/2023/05/identity/dateofbirth", user.DateOfBirth.ToShortDateString()));
return claims;
}
}
public class MinimumAgeRequirement : IAuthorizationRequirement
{
public MinimumAgeRequirement(int minimumAge)
{
MinimumAge = minimumAge;
}
public int MinimumAge { get; }
}
public class MinimumAgeHandler : IAuthorizationHandler
{
public async Task HandleAsync(AuthorizationHandlerContext context)
{
foreach (var item in context.PendingRequirements)
{
switch (item)
{
case MinimumAgeRequirement r:
await HandleMinimumAgeRequirement(context, r);
break;
};
}
}
protected async Task HandleMinimumAgeRequirement(AuthorizationHandlerContext context, MinimumAgeRequirement requirement)
{
var ageClaim = context.User.Claims.SingleOrDefault(c => c.Type == "http://schemas.techeddemo.com/2023/05/identity/dateofbirth");
if (ageClaim!=null && DateTime.Now.Subtract(DateTime.Parse(ageClaim.Value)) > TimeSpan.FromDays(requirement.MinimumAge * 365))
context.Succeed(requirement);
}
}
public sealed class MinimumAgeAttribute : AuthorizeAttribute
{
private static readonly string policyPrefix = "minimumAge:";
public MinimumAgeAttribute(int minimumAge)
{
MinimumAge = minimumAge;
}
public int MinimumAge
{
get => int.Parse(Policy.Substring(policyPrefix.Length));
set => Policy = $"{policyPrefix}{value}";
}
}
public class MinimumAgePolicyProvider : DefaultAuthorizationPolicyProvider
{
private static readonly string policyPrefix = "minimumAge:";
public MinimumAgePolicyProvider(IOptions<AuthorizationOptions> options) : base(options) { }
public async override Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
if (policyName.StartsWith(policyPrefix, StringComparison.OrdinalIgnoreCase))
{
var minimumAge = int.Parse(policyName.Substring(policyPrefix.Length));
var policy = new AuthorizationPolicyBuilder();
policy.AddRequirements(new MinimumAgeRequirement(minimumAge));
return policy.Build();
}
return await base.GetPolicyAsync(policyName);
}
}
builder.Services.AddIdentity<ApplicationUser, IdentityRole>(opts => opts.Stores.ProtectPersonalData = true)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddClaimsPrincipalFactory<CustomClaimFactory>();
builder.Services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment