Asp.net “disable” authentication in development environment

后端 未结 5 880
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-06 04:27

Is it possible to \"disable\" authentication in asp.net core application without changing its logic?

I have a .net website which uses an external identity server app

相关标签:
5条回答
  • 2020-12-06 04:49

    In ASP.NET Core 3.x and later, you can change Startup.Configure() method as shown below in order to add AllowAnonymousAttribute to your controllers:

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // ...
        app.UseEndpoints(endpoints =>
        {
            if (env.IsDevelopment())
                endpoints.MapControllers().WithMetadata(new AllowAnonymousAttribute());
            else
                endpoints.MapControllers();
        });
    }
    

    Note that this will add AllowAnonymousAttribute to all controllers. AllowAnonymousAttribute's description from the docs:

    Specifies that the class or method that this attribute is applied to does not require authorization.

    0 讨论(0)
  • 2020-12-06 04:53

    It's tricky to give a detailed answer without more details on your end, but I have previously achieved this by conditionally registering:

    • the external authentication middleware
    • the global policy that requires an authenticated request

    it looked something like:

    public class Startup
    {
        public Startup(IHostingEnvironment env)
        {
            Environment = env;
        }
    
        public IHostingEnvironment Environment { get; }
    
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(x =>
            {
                if (!Environment.IsDevelopment())
                {
                    var authenticatedUserPolicy = new AuthorizationPolicyBuilder()
                        .RequireAuthenticatedUser()
                        .Build();
    
                    x.Filters.Add(new AuthorizeFilter(authenticatedUserPolicy));
                }
            });
        }
    
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            app.UseStaticFiles();
    
            if (!Environment.IsDevelopment())
            {
                // Register external authentication middleware
            }
    
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
    

    In my case, the authorization filter was applied globally, so every single action of the MVC app required an authenticated user.

    If you have different requirements - fine-grained [Authorize] attributes on some actions - then you could probably achieve the same result by changing how the associated authorization policies are built. They could basically contain no requirements at all.

    AuthorizationPolicy yourCustomPolicy = null;
    if (Environment.IsDevelopment())
    {
        yourCustomPolicy = new AuthorizationPolicyBuilder().Build();
    }
    else
    {
        yourCustomPolicy = new AuthorizationPolicyBuilder()
            // chaining appropriate methods to suit your needs
            .Build();
    }
    
    0 讨论(0)
  • 2020-12-06 04:56

    I've found sollution for this problem on illucIT Blog.

    This code must work:

    if (env.IsDevelopment()) {
       services.AddMvc(opts =>
       {
          opts.Filters.Add(new AllowAnonymousFilter());
       });
    } else {
       services.AddMvc();
    }
    
    0 讨论(0)
  • 2020-12-06 05:02

    Another solution you may want to consider is using the IPolicyEvaluator. This means that you can keep all the existing security elements.

    public class DisableAuthenticationPolicyEvaluator : IPolicyEvaluator
    {
        public async Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
        {
            // Always pass authentication.
            var authenticationTicket = new AuthenticationTicket(new ClaimsPrincipal(), new AuthenticationProperties(), JwtBearerDefaults.AuthenticationScheme);
            return await Task.FromResult(AuthenticateResult.Success(authenticationTicket));
        }
    
        public async Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource)
        {
            // Always pass authorization
            return await Task.FromResult(PolicyAuthorizationResult.Success());
        }
    }
    

    In the Startup.cs, ensure this appears at the top of the ConfigureServices method. Eg.

        public void ConfigureServices(IServiceCollection services)
        {
            if (env.IsDevelopment())
            {
                // Disable authentication and authorization.
                services.TryAddSingleton<IPolicyEvaluator, DisableAuthenticationPolicyEvaluator>();
            }
            ...
    

    Rather than Startup.cs (and thanks to the comments below) if you are using Core 3.1 and you wish to use the WebApplicationFactory, you can do the following:

    public class MyWebApplicationFactory : WebApplicationFactory<Program>
    {
        protected override void ConfigureWebHost(IWebHostBuilder builder)
        {
            builder.ConfigureTestServices(services =>
            {
                // Disable Authentication.
                services.RemoveAll<IPolicyEvaluator>();
                services.AddSingleton<IPolicyEvaluator, DisableAuthenticationPolicyEvaluator>();
            });
        }
    }
    
    0 讨论(0)
  • 2020-12-06 05:04

    On updating to net core 3.1, the mvc AllowAnonymousFilter was not working for us any more. We found conditionally adding a custom IAuthorizationHander to be the simplest way forward to conditionally bypass auth.

    eg.

    /// <summary>
    /// This authorisation handler will bypass all requirements
    /// </summary>
    public class AllowAnonymous : IAuthorizationHandler
    {
        public Task HandleAsync(AuthorizationHandlerContext context)
        {
            foreach (IAuthorizationRequirement requirement in context.PendingRequirements.ToList())
                context.Succeed(requirement); //Simply pass all requirements
    
            return Task.CompletedTask;
        }
    }
    

    Then register this handler conditionally in Startup.ConfigureServices.

    private readonly IWebHostEnvironment _env;
    public Startup(IWebHostEnvironment env)
    {
        _env = env;
    }
    
    public void ConfigureServices(IServiceCollection services)
    {
      {...}
    
      //Allows auth to be bypassed
      if (_env.IsDevelopment())
        services.AddSingleton<IAuthorizationHandler, AllowAnonymous>();
    }
    
    

    Note AddAuthentication and AddAuthorization services are still registered and configured as per prod code (which is nice).

    To allow our unit test to bypass auth we added a new anonymous testbase with a startup class that added line this line without any conditions. Nice and simple!

    0 讨论(0)
提交回复
热议问题