Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
322 views
in Technique[技术] by (71.8m points)

authorize - Asp.net core, when in debug, bypass Authorization

I have a test web site which uses the aspnetCore [AuthorizeAttribute] at the entire controller level to ensure only Authenticated Users can hit this site.

While we debug and test new features, we constantly have to comment out the attribute in each controller, which I know will be easy to forget and might get merged some day.

We've had good success with checking to see if a Debugger is attached before...I am wondering which AuthenticationScheme I should specify to allow anonymous, only if debugging.

I extend the base AuthorizeAttribute so I have an easy place to shim in some code.

public class MyAppAuthorizeAttribute : AuthorizeAttribute
    {
        public MyAppAuthorizeAttribute()
            : base(Policies.MyAppAuthorize)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                Console.WriteLine("Skipping auth for debug");        //we hit this line but...
                this.AuthenticationSchemes = AllowAnonymousAttribute //this setting does not work
            }
            else
            {
                this.AuthenticationSchemes = "IntegratedWindowsAuthentication";
            }
            
        }
    }
question from:https://stackoverflow.com/questions/65888337/asp-net-core-when-in-debug-bypass-authorization

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your requirement may be necessary in some cases where the user is required to be authenticated BUT not actually referenced in the code (e.g: the code does not access any info on the current identity, especially related to the business model of the user). So I assume that you are aware of that because the following will just simply remove the requirement to check for authenticated user when the code runs in the development environment. There is another way to auto sign-in a dummy user which can be better in some scenarios.

Here is the first solution, it configures a default policy only which does not include the DenyAnonymousAuthorizationRequirement (which is the only requirement contained in the default policy). That means if you have multiple policies used somewhere (with AuthorizeAttribute), only the default will be ignored (while debugging). The second solution (shown later) may suit that scenario better.

//inject IHostingEnvironment in the Startup constructor
public Startup(IConfiguration configuration, IHostingEnvironment env){
   HostingEnvironment = env;
}
public IHostingEnvironment HostingEnvironment { get; }

//in the ConfigureServices method in Startup.cs
services.AddAuthorization(o => {
    if (HostingEnvironment.IsDevelopment()){
       o.DefaultPolicy = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme)
                         //there should be at least 1 requirement
                         //here we add a simple always-passed assertion
                         .RequireAssertion(e => true).Build();
    }         
    //...
});

We need to use IHostingEnvironment (in .net core 2.2, since 3.0 we have 2 alternatives IWebHostEnvironment and IHostEnvironment) so we inject it in the Startup constructor and store it in a readonly property (as you see above). There is another way is try to get the ASPNETCORE_ENVIRONMENT variable directly like this:

var isDevelopment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";

Here is the second solution in which you use a custom global IAsyncAuthorizationFilter to auto sign-in a dummy user (so it's always authenticated for all requests).

public class AllowAnonymousFilterAttribute : Attribute, IAsyncAuthorizationFilter
{
    readonly IHostingEnvironment _hostingEnvironment;
    public AllowAnonymousFilterAttribute(IHostingEnvironment env){
       _hostingEnvironment = env;
    }
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        if (_hostingEnvironment.IsDevelopment() && !context.HttpContext.User.Identity.IsAuthenticated)
        {
            //prepare a dummy user to auto sign-in
            HttpContext.User = new ClaimsPrincipal(new[] {
                new ClaimsIdentity(new []{ new Claim(ClaimTypes.NameIdentifier,"admin")},
                                   CookieAuthenticationDefaults.AuthenticationScheme)
            });
            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, 
                                          HttpContext.User);
        }
    }
}

Register the filter globally, here I write code for .net core 2.2:

services.AddMvc(o => {
     //register the filter only for development (should be debugging)
     if (HostingEnvironment.IsDevelopment()){
       o.Filters.Add<AllowAnonymousFilterAttribute>();
     }
     //...
});

I'm sure there are still some other solutions but what I've introduced here are fairly simple and good enough for your purpose.

P/S: the first solution I've introduced above suits for .net core 2.2 (actually currently I do not have access to newer versions of .net core, it's a pity). For the newer versions, the Authorization middleware is separate so you may just simply not call .UseAuthorization() middleware in the Configure method (of course for development environment only) as one other answer suggests.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...