ASP.NET Core 2.0 disables automatic task

After upgrading my ASP.NET Core project to version 2.0, attempts to access secure endpoints no longer return 401, but are redirected to a (non-existent) endpoint, trying to give the user the option of authentication.

The desired behavior for the application is simply to return 401. Previously, I set AutomaticChallenge = false when setting up authentication, but according to this article, the setting is no longer relevant (in fact, it no longer exists).

My authentication is configured as follows:

Startup.cs.ConfigureServices ():

 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(o => { o.Cookie.Name = options.CookieName; o.Cookie.Domain = options.CookieDomain; o.SlidingExpiration = true; o.ExpireTimeSpan = options.CookieLifetime; o.TicketDataFormat = ticketFormat; o.CookieManager = new CustomChunkingCookieManager(); }); 

Setting ():

 app.UseAuthentication(); 

How to disable automatic calling so that the application returns 401 when the user is not authenticated?

+14
authentication c # asp.net-core asp.net-core-mvc
source share
8 answers

As indicated in some other answers, there is no longer a setting to disable automatic calling using cookie authentication. The solution is to override OnRedirectToLogin :

 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.Events.OnRedirectToLogin = context => { context.Response.Headers["Location"] = context.RedirectUri; context.Response.StatusCode = 401; return Task.CompletedTask; }; }); 

This may change in the future: https://github.com/aspnet/Security/issues/1394

+24
source share

After some research, I found that we can deal with this problem, although below:

We can add two authentication schemes, both Identity and JWT; and use the authentication scheme for authentication and use the JWT scheme for the call, the JWT will not be redirected to any login during the call.

 services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>(); services.AddAuthentication((cfg => { cfg.DefaultScheme = IdentityConstants.ApplicationScheme; cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; })).AddJwtBearer(); 
+20
source share

According to this article :

In 1.x, the AutomaticAuthenticate and AutomaticChallenge properties had to be set on a single authentication scheme. There was no good way to secure this.

In 2.0, these two properties were removed as flags in a separate Authentication instance and moved to the base class AuthenticationOptions. Properties can be configured by calling the AddAuthentication method in the ConfigureServices method Startup.cs

 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme); 

Alternatively, use the overloaded version of the AddAuthentication method to set more than one property. In the following overloaded method example, the default scheme is set to CookieAuthenticationDefaults.AuthenticationScheme. An authentication scheme can alternatively be specified in your individual [Authorize] attributes or authorization policies.

 services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }); 

Define a default schema in 2.0 if one of the following conditions is true:

  • You want the user to automatically subscribe to
  • You use the [Authorize] attribute or authorization policies without specifying a scheme

An exception to this rule is the AddIdentity method. This method adds cookies for you and sets the default authentication and calling patterns in the cookie of the IdentityConstants.ApplicationScheme application. In addition, it sets the default login scheme for the external cookie IdentityConstants.ExternalScheme .

Hope this helps you.

+4
source share

It is compatible with @Serverin by setting OnRedirectToLogin in the cookie application, but must be executed in the instructions of the following services. AddIdentity in Startup.cs: ConfigureServices:

 services.ConfigureApplicationCookie(options => { options.Events.OnRedirectToLogin = context => { context.Response.Headers["Location"] = context.RedirectUri; context.Response.StatusCode = 401; return Task.CompletedTask; }; }); 
+4
source share

This is the source code of CookieAuthenticationEvents.OnRedirectToLogin:

 public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToLogin { get; set; } = context => { if (IsAjaxRequest(context.Request)) { context.Response.Headers["Location"] = context.RedirectUri; context.Response.StatusCode = 401; } else { context.Response.Redirect(context.RedirectUri); } return Task.CompletedTask; }; 

You can add the "X-Requested-With: XMLHttpRequest" header to the request when calling the API from your client.

+3
source share

I am not sure how to generate error 401, however, if you use:

 o.AccessDeniedPath = "{path to invalid}"; 

This will allow you to redirect somewhere when the call failed.

0
source share

Another way to make this more convenient for DI / testing is to use AuthenticationSchemeOptions.EventsType (another answer to this question here ). This will allow you to include other components in the resolution process.

Here is an example that includes registration and permission, which stops the default redirection for logging on to an unauthenticated request and instead simply returns a hard 401 . It also has a slot for any other dependencies you may need to know about unauthenticated requests.

In Startup.cs :

 services .AddAuthentication("MyAuthScheme") .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.EventsType = typeof(MyEventsWrapper); }; ... services.AddTransient<MyEventsWrapper>(); services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 

Then in MyEventsWrapper.cs :

 public class MyEventsWrapper : CookieAuthenticationEvents { private readonly IHttpContextAccessor _accessor; private readonly IDependency _otherDependency; public MyEventsWrapper(IHttpContextAccessor accessor, IDependency otherDependency) { _accessor = accessor; _otherDependency = otherDependency; } public override async Task RedirectToLogin(RedirectContext<CookieAuthenticationOptions> context) { context.Response.Headers.Remove("Location"); context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; await _otherDependency.Cleanup(_accessor.HttpContext); } } 
0
source share

I found that in most cases the solution is to override

OnRedirectToLogin

But in my application, I used several authentication policies and overriding OnRedirectToLogin did not work for me. The solution in my case was to add simple middleware to redirect the incoming request.

 app.Use(async (HttpContext context, Func<Task> next) => { await next.Invoke(); //execute the request pipeline if (context.Response.StatusCode == StatusCodes.Status302Found && context.Response.Headers.TryGetValue("Location", out var redirect)) { var v = redirect.ToString(); if (v.StartsWith($"{context.Request.Scheme}://{context.Request.Host}/Account/Login")) { context.Response.Headers["Location"] = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}"; context.Response.StatusCode = 401; } } }); 
0
source share

All Articles