ASP.NET Core 6 Web API - How do I check if the action with given ActionDescriptor requires authentication?

Viewed 212

Given an ActionDescriptor, for example the ActionDescriptor of the action located at GET /api/Item/{id}, how do I tell if it requires authentication or not?
Checking if filters of the method corresponding to the action, and possibly the filters of the class that declares the method are AuthorizeAttribute or AllowAnonymousAttribute is not reliable because in this way the policies of AuthorizationOptions (FallbackPolicy, DefaultPolicy and the policies added with AddPolicy()) would not be taken into consideration, for example.
I tried to check if the following interfaces had a method that accepts an ActionDescriptor, but unfortunately none of them have it:

  • IAuthorizationPolicyProvider
  • IAuthorizationService
  • IAuthorizationHandler
  • IAuthorizationHandlerContextFactory
  • IAuthorizationHandlerProvider

EDIT: after searching a bit, I think what I need existed in WebForms: UrlAuthorizationModule.CheckUrlAccessForPrincipal(). I wonder if there is something similar for ASP.NET Core.

1 Answers

You need to check the filters with the authorization interfaces, so I think this should work:

if(ControllerContext.ActionDescriptor.FilterDescriptors.OfType<IAuthorizationFilter>().Any())
 //means the action has Authorization filter
        
if(ControllerContext.ActionDescriptor.FilterDescriptors.OfType<IAllowAnonymous>().Any())
 //means action has AllowAnonymous filter

Update: Another way is to get all actions with their attributes

var projectAssembly = Assembly.GetAssembly(typeof(Suxxeed.Analytixx.Api.Startup));
var controllerActionlist = projectAssembly.GetTypes()
            .Where(type => typeof(Controller).IsAssignableFrom(type))
            .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
            .Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), true).Any())
            .Select(x => new
            {
                Controller = x.DeclaringType?.Name,
                ControllerAttributes = string. Join(",", x.DeclaringType.GetCustomAttributes().Select(a => a.GetType().Name.Replace("Attribute", ""))),
                Action = x.Name,
                ActionAttributes = string. Join(",", x.GetCustomAttributes().Select(a => a.GetType().Name.Replace("Attribute", "")))
            })
            .OrderBy(x => x.Controller).ThenBy(x => x.Action).ToList();

//for detecting any action has Authorize attribute you can do this
if(controllerActionlist.Any(x=> x.Action=="YouAction" 
&& (x.ActionAttributes.Contains("Authorize") || x.ControllerAttributes.Contains("Authorize"))))
   //some stuff
Related