asp.net-core-webapiasp.net-authorizationpolicy-based-security

Same Policy but different required parameter for each action method


In a .Net core Webapi 2.1 project, I have a tons of action methods.
All action methods should be authorized against the same policy (named FooPolicy) but with a different required argument.
Based on Microsoft's docs: Policy-based-Authorization One way would be to declare a tons of policies based on different input argument:

services.AddAuthorization(options =>
{
    options.AddPolicy("FooPolicy1", policy =>policy.Requirements.Add(new FooRequirement(1)));
    options.AddPolicy("FooPolicy2", policy =>policy.Requirements.Add(new FooRequirement(2)));
    options.AddPolicy("FooPolicy3", policy =>policy.Requirements.Add(new FooRequirement(3)));
    //... May be 30 more same policies here ...
});

As i earlier mentioned, only different part is in new FooRequirement(diffArgs). The other challenge for this solution would be to add each FooPolicy on it's corresponding action method and you may miss a couple of theme:

[Authorize(Policy = "FooPolicy1")]
public IActionResult ActionMethodFoo1(...) {...}

[Authorize(Policy = "FooPolicy2")]
public IActionResult ActionMethodFoo2(...) {...}

[Authorize(Policy = "FooPolicy3")]
public IActionResult ActionMethodFoo3(...) {...}
...List still goes on...

Is there any solution like: declare a policy once but use it with different instance of FooRequirement (which is of type IAuthorizationHandler)? like so:

services.AddAuthorization(options =>
{
    options.AddPolicy("FooPolicy", policy =>policy.Requirements.Add(?));
});

And on the action methods:

[Authorize(Policy = "FooPolicy", required = new FooRequirement(1))]
public IActionResult ActionMethodFoo1(...) {...}

[Authorize(Policy = "FooPolicy", required = new FooRequirement(2))]
public IActionResult ActionMethodFoo2(...) {...}

[Authorize(Policy = "FooPolicy", required = new FooRequirement(3))]
public IActionResult ActionMethodFoo3(...) {...}

The main idea is to declare policy once. Two recent code blocks are psudo-code, Does any body knows practical solution with similar concept?


Solution

  • You could implement your own IAuthorizationFilter

    1. custom IAuthorizationFilter

      public class CustomAuthorize : IAuthorizationFilter         
       {
              private readonly int _input;
      
      public CustomAuthorize(int input)
      {
          _input = input;
      }
      
      public void OnAuthorization(AuthorizationFilterContext context)
      {
          //custom validation rule
          if (_input == 1)
          {
              context.Result = new ForbidResult();
          }
      }
      }
      
    2. Custom CustomAuthorizeAttribute

      public class CustomAuthorizeAttribute : TypeFilterAttribute
      {
      public CustomAuthorizeAttribute(int input) : base(typeof(CustomAuthorize))
      {
          Arguments = new object[] { input };
      }
      }
      
    3. Use

      [CustomAuthorizeAttribute(1)]
      public IActionResult About()