.NET Core API Conditional Authentication attributes for Development & Production .NET Core API Conditional Authentication attributes for Development & Production asp.net asp.net

.NET Core API Conditional Authentication attributes for Development & Production


ASP.NET Core authorization is based on policies. As you may have seen, the AuthorizeAttribute can take a policy name so it knows which criteria need to be satisfied for the request to be authorized. I suggest that you have a read of the great documentation on that subject.

Back to your problem, it looks like you don't use a specific policy, so it uses the default one, which requires the user to be authenticated by default.

You can change that behaviour in Startup.cs. If you're in development mode, you can redefine the default policy so that it doesn't have any requirements:

public void ConfigureServices(IServiceCollection services){    services.AddAuthorization(x =>    {        // _env is of type IHostingEnvironment, which you can inject in        // the ctor of Startup        if (_env.IsDevelopment())        {            x.DefaultPolicy = new AuthorizationPolicyBuilder().Build();        }    });}

Update

im1dermike mentioned in a comment that an AuthorizationPolicy needs at least one requirement, as we can see here. That code wasn't introduced recently, so it means the solution above was broken the whole time.

To work around this, we can still leverage the RequireAssertion method of AuthorizationPolicyBuilder and add a dummy requirement. This would look like:

public void ConfigureServices(IServiceCollection services){    services.AddAuthorization(x =>    {        // _env is of type IHostingEnvironment, which you can inject in        // the ctor of Startup        if (_env.IsDevelopment())        {            x.DefaultPolicy = new AuthorizationPolicyBuilder()                .RequireAssertion(_ => true)                .Build();        }    });}

This ensures we have at least one requirement in the authorization policy, and we know that it will always pass.


I end up with this, might help :

    public class OnlyDebugModeAttribute : ActionFilterAttribute{    public override void OnActionExecuted(ActionExecutedContext context)    {        base.OnActionExecuted(context);    }    public override void OnActionExecuting(ActionExecutingContext context)    {#if DEBUG        //Ok#else        context.Result = new ForbidResult();        return;#endif    }}

and then apply it on controler

[OnlyDebugMode][Route("api/[controller]")][ApiController]public class DebugController : ControllerBase{ 


Here's my solution:

New attribute for your controllers:

[AzureADAuthorize]

AzureADAuthorize.cs:

public class AzureADAuthorize : AuthorizeAttribute    {        public AzureADAuthorize() : base(AzureADPolicies.Name)        {        }    }

AzureADPolicies.cs:

public static class AzureADPolicies    {        public static string Name => "AzureADAuthorizationRequired";        public static void Build(AuthorizationPolicyBuilder builder)            {                if (StaticRepo.Configuration.GetValue<bool>("EnableAuthorization") == true)                {                    var section = StaticRepo.Configuration.GetSection($"AzureAd:AuthorizedAdGroups");                    var groups = section.Get<string[]>();                    builder.RequireClaim("groups", groups);                }                else if (StaticRepo.Configuration.GetValue<bool>("EnableAuthentication") == true)                {                    builder.RequireAuthenticatedUser();                }else                {                    builder                    .RequireAssertion(_ => true)                    .Build();                }                         }    }

Startup.cs:

//Authentication & Authorization            #region AUTHENTICATION / AUTHORICATION            StaticRepo.Configuration = Configuration;                services.AddAuthorization(options =>                {                    options.AddPolicy(                        AzureADPolicies.Name, AzureADPolicies.Build);                });            services.AddAuthentication(AzureADDefaults.AuthenticationScheme)             .AddAzureAD(options => Configuration.Bind("AzureAd", options));            #endregion

Appsettings.json:

 "EnableAuditLogging": false,  "EnableAuthentication": true,  "EnableAuthorization": false,"AzureAd": {    "Instance": "https://login.microsoftonline.com/",    "Domain": "https://MyDomain.onmicrosoft.com/",    "TenantId": "b6909603-e5a8-497d-8fdb-7f10240fdd10",    "ClientId": "6d09a1bf-4678-4aee-b67c-2d6df68d5324",    "CallbackPath": "/signin-oidc",    //Your Azure AD Security Group Object IDs that users needs to be member of to gain access    "AuthorizedAdGroups": [      "568bd325-283f-4909-9fcc-a493d19f98e8",      "eee6d366-0f4d-4fca-9965-b2bc0770506d"    ]  }

(These are random guids)

Now you can conditional control if you want to have anonymous access, azure ad authentication, authentication + group authorization. There are still some stuff you need to setup in your azure ad app manifest file to get it to work, but I think it's outside the scope here.