ASP.NET CORE - How to using IAuthorizationRequirementData
Source: Dev.to
Scenarios may be useful
- Using an external service to provide policy evaluation.
- Using a large range of policies, so it doesn’t make sense to add each individual authorization policy with an
AuthorizationOptions.AddPolicycall. - Creating policies at runtime based on information in an external data source (like a database) or determining authorization requirements dynamically through another mechanism.
Applied: from ASP.NET Core 8
Step 1: Implement a custom Authorize attribute
using Microsoft.AspNetCore.Authorization;
using System;
using System.Collections.Generic;
namespace PracticalAPI.AuthorizationRequirementData
{
public enum FeatureOperator
{
And = 1,
Or = 2
}
public class UserFeatureAuthorizeAttribute : AuthorizeAttribute,
IAuthorizationRequirement,
IAuthorizationRequirementData
{
internal const string PolicyPrefix = "UserFeature_";
public FeatureOperator Operator { get; set; }
public string[] Features { get; set; }
public UserFeatureAuthorizeAttribute(FeatureOperator featureOperator, params string[] features)
{
Operator = featureOperator;
Features = features;
}
public UserFeatureAuthorizeAttribute(string feature)
{
Operator = FeatureOperator.And;
Features = new[] { feature };
}
public IEnumerable GetRequirements()
{
yield return this;
}
}
}
Step 2: Implement the AuthorizationHandler
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Logging;
using System.Globalization;
using System.Threading.Tasks;
using System;
namespace PracticalAPI.AuthorizationRequirementData
{
public class UserFeatureAuthorizationHandler : AuthorizationHandler
{
private readonly ILogger _logger;
private static string featureType = "feature";
public UserFeatureAuthorizationHandler(ILogger logger)
{
_logger = logger;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
UserFeatureAuthorizeAttribute requirement)
{
if (requirement.Operator == FeatureOperator.And)
{
foreach (var feature in requirement.Features)
{
_logger.LogWarning("Evaluating authorization requirement for feature: {Feature}", feature);
if (!context.User.HasClaim(featureType, feature))
{
context.Fail();
return Task.CompletedTask;
}
}
context.Succeed(requirement);
return Task.CompletedTask;
}
foreach (var feature in requirement.Features)
{
_logger.LogWarning("Evaluating authorization requirement for feature: {Feature}", feature);
if (context.User.HasClaim(featureType, feature))
{
context.Succeed(requirement);
return Task.CompletedTask;
}
}
context.Fail();
return Task.CompletedTask;
}
}
}
Step 3: Register the UserFeatureAuthorizationHandler
using AuthRequirementsData.Authorization;
using Microsoft.AspNetCore.Authorization;
var builder = WebApplication.CreateBuilder();
// ...
// Use custom authorization
// builder.Services.AddSingleton();
var app = builder.Build();
app.MapControllers();
app.Run();
Step 4: Use the custom authorization attribute in a controller
[UserFeatureAuthorize("Feature1")]
public async Task> MyAction([FromBody] RequestModel model)
{
// Logic code goes here
}
This is one of many options you can use to implement robust authorization for your application. Choose the approach that best fits your scenario.
Happy coding!