I have an API controller
[ApiController]
public class DataController : ControllerBase
{
public ActionResult Get1()
{}
[Authorize]
public ActionResult Get2()
{}
[Authorize(Role="xxx")]
public ActionResult Get3()
{}
}
In my Startup I've specified:
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder().AddRequirements(new DataRequirement()).Build();
options.FallbackPolicy = new AuthorizationPolicyBuilder().AddRequirements(new DataRequirement()).Build();
});
Which takes care of the Get1
(fallback) and Get2
(default).
But how can I customize a Policy handling this decoration [Authorize(Role="xxx")]
?
I actually don't want to use the Role
-parameter, but rather something like [Authorize(RoleSuffix="_yyy")]
coz I can't enter the full AdGroup name, only the last part. And that's why I need to customize this.
Requirements:
- I don't want to use a FilterAttribute, which works great eg:
[DoAuthorize("_xxx")]
- I can't change in AD and put groups in groups etc
The closest thing I've come up with is to specify a Policy in the decoration [Authorize(Policy = "policy")]
but how can I specify a suffix-parameter to this policy? I don't want to create 1 policy per suffix. I would like to specify the suffix at the method.
The reason I need to customize a lot here: I have a few special groups that should have access to everything, and a few based on the group's suffix, and one basic default for methods with no suffix specified.
Any ideas here?
CodePudding user response:
Check Parameterized authorize attribute example.
Here is an example of how you can implement this for your scenario:
public class SuffixAuthorizeAttribute : AuthorizeAttribute
{
const string POLICY_PREFIX = "RoleSuffix";
public SuffixAuthorizeAttribute(string suffix) => Suffix = suffix;
public string Suffix
{
get
{
return Policy == null ? string.Empty : Policy[POLICY_PREFIX.Length..];
}
set
{
Policy = $"{POLICY_PREFIX}{value}";
}
}
}
public class SuffixPolicyProvider : IAuthorizationPolicyProvider
{
const string POLICY_PREFIX = "RoleSuffix";
private DefaultAuthorizationPolicyProvider BackupPolicyProvider { get; }
public SuffixPolicyProvider(IOptions<AuthorizationOptions> options)
{
BackupPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
=> BackupPolicyProvider.GetDefaultPolicyAsync();
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
=> BackupPolicyProvider.GetFallbackPolicyAsync();
public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
{
if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase))
{
var suffix = policyName[POLICY_PREFIX.Length..];
var policy = new AuthorizationPolicyBuilder();
policy.RequireAssertion(
context => context.User.HasClaim(c => c.Type == ClaimTypes.Role && c.Value.EndsWith(suffix)));
return Task.FromResult(policy?.Build());
}
return BackupPolicyProvider.GetPolicyAsync(policyName);
}
}
Register the custom IAuthorizationPolicyProvider
:
builder.Services.AddSingleton<IAuthorizationPolicyProvider, SuffixPolicyProvider>();
Use like this:
[SuffixAuthorize("_yyy")]
public ActionResult Get3()
{
}
this is the equivalent of doing: [Authorize(Policy = "RoleSuffix_yyy")]
. Only difference is you don't have to create a policy for each suffix because the policy is created "dynamically" from the custom IAuthorizationPolicyProvider
.