ASP.NET Core 2.0 Disable Automatic Challenge

ASP.NET Core 2.0 disable automatic challenge

Similiar to @Serverin, setting the OnRedirectToLogin of the Application Cookie worked, but must be done in statement 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;
};
});

Turn off AutomaticChallenge in asp.net mvc core 2 OpenIdConnect

The best solution I've been able to come with so far is:

services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.Events.OnRedirectToAccessDenied = DontRedirectAjaxOrApiRequestToForbidden;
})
.AddOpenIdConnect(options =>
{
...
options.Events.OnRedirectToIdentityProvider = DontRedirectAjaxRequestToOpenIdProvider;
});

/// <summary>
/// Unauthenticated ajax or API request returns 403 rather than Redirect to forbidden page
/// </summary>
private static Task DontRedirectAjaxOrApiRequestToForbidden(RedirectContext<CookieAuthenticationOptions> ctx)
{
bool isAjaxRequest = ctx.HttpContext.Request.Headers["x-requested-with"] == "XMLHttpRequest";
if (isAjaxRequest || (ctx.Request.Path.StartsWithSegments("/api")))
{
ctx.Response.StatusCode = 403;
}
else
{
ctx.Response.Redirect(ctx.RedirectUri);
}
return Task.CompletedTask;
}

/// <summary>
/// Unauthenticated ajax request returns 401 rather than Redirect
/// </summary>
private static Task DontRedirectAjaxRequestToOpenIdProvider(RedirectContext redirectContext)
{
bool isAjaxRequest = redirectContext.HttpContext.Request.Headers["x-requested-with"] == "XMLHttpRequest";
if (isAjaxRequest)
{
redirectContext.HttpContext.Response.StatusCode = StatusCodes.Status401Unauthorized;
redirectContext.HttpContext.Response.Headers["Location"] = CookieAuthenticationDefaults.LoginPath.Value;
redirectContext.HandleResponse();
}
return Task.CompletedTask;
}

Prevent redirect to /Account/Login in asp.net core 2.2

Hey there and welcome to StackOverflow /p>

The behaviour you experience is linked to the fact that you use ASP.NET Identity.
When you call services.AddIdentity, behind the scenes a cookie-based authentication scheme is registered and set as the default challenge scheme, as you can see in the code here on GitHub.

Even though you registered a cookie authentication scheme yourself and set it as the default scheme, the specific default schemes — like AuthenticateScheme, ChallengeScheme, SignInScheme, etc... — take precendence. DefaultScheme is used by the authentication system only when the specific one is not set.

To answer your question, you could apply the configuration settings to the ASP.NET Identity cookie options by using the helper method services.ConfigureApplicationCookie, like so:

// ===== Add Identity ========
services.AddIdentity<User, IdentityRole>(o =>
{
o.User.RequireUniqueEmail = true;
o.Tokens.EmailConfirmationTokenProvider = "EMAILCONF";
// I want to be able to resend an `Email` confirmation email
// o.SignIn.RequireConfirmedEmail = true;
}).AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ContestContext>()
.AddTokenProvider<EmailConfirmationTokenProvider<User>>("EMAILCONF")
.AddDefaultTokenProviders();

services.Configure<DataProtectionTokenProviderOptions>(o =>
o.TokenLifespan = TimeSpan.FromHours(3)
);

services.Configure<EmailConfirmationTokenProviderOptions>(o =>
o.TokenLifespan = TimeSpan.FromDays(2)
);

// ===== Configure Identity =======
service.ConfigureApplicationCookie(options =>
{
options.Cookie.Name = "auth_cookie";
options.Cookie.SameSite = SameSiteMode.None;
options.LoginPath = new PathString("/api/contests");
options.AccessDeniedPath = new PathString("/api/contests");

// Not creating a new object since ASP.NET Identity has created
// one already and hooked to the OnValidatePrincipal event.
// See https://github.com/aspnet/AspNetCore/blob/5a64688d8e192cacffda9440e8725c1ed41a30cf/src/Identity/src/Identity/IdentityServiceCollectionExtensions.cs#L56
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
};
});

It also means that you can safely remove the part where you add a cookie-based authentication scheme since this is taken care of by ASP.NET Identity itself.

Let me know how you go!

.NET core 2.0 cookie authentication - do not redirect

Unfortunately the flag is well and truly removed. However you can override the "RedirectToLogin" event like so in your ConfigureServices method of your startup.cs

services.AddAuthentication("CookieAuthenticationScheme")
.AddCookie(options => {
options.Events.OnRedirectToLogin = (context) =>
{
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
});

Couple more tidbits here if you get stuck on the upgrade : https://dotnetcoretutorials.com/2017/09/16/cookie-authentication-asp-net-core-2-0/

Am I right to assume this is because it's an ajax call you are making (Or a Web API in general?). It seems like MS have gone hard with JWT being for Web API, and for Cookie to be for MVC only. Hence why the forced login page.

.NET Core 2.0 Cookie Events OnRedirectToLogin

I was able to get it working as I wanted, so I am posting my answer in case anyone else comes across this question. With the help of this documentation: Use cookie authentication without ASP.NET Core Identity. I implemented the CustomCookieAuthenticationEvents and casted that as the type for the Cookie events.

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(o =>
{
o.AccessDeniedPath = new PathString("/Error/AccessDenied");
o.LoginPath = new PathString("/Account/Login/");
o.Cookie.Path = "/";
o.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
o.Cookie.HttpOnly = true;
o.LogoutPath = new PathString("/Account/Logout/");
//This line here
o.EventsType = typeof(CustomCookieAuthenticationEvents);
});

//register the IActionContextAccessor so that I can inject into my CustomCookieAuthenticationEvents constructor
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();

Then inside that Custom class, I was able to inject IUrlHelperFactory and IActionContextAccessor which helps me create new UrlHelper for the current action.

public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{
private IUrlHelperFactory _helper;
private IActionContextAccessor _accessor;
public CustomCookieAuthenticationEvents(IUrlHelperFactory helper, IActionContextAccessor accessor)
{
_helper = helper;
_accessor = accessor;
}
public override Task RedirectToLogin(RedirectContext<CookieAuthenticationOptions> context)
{
var routeData = context.Request.HttpContext.GetRouteData();
RouteValueDictionary routeValues = new RouteValueDictionary();
//Create new routeValues based on routeData above
... code removed for brevity
Uri uri = new Uri(context.RedirectUri);
string returnUrl = HttpUtility.ParseQueryString(uri.Query)[context.Options.ReturnUrlParameter];

routeValues.Add(context.Options.ReturnUrlParameter, returnUrl + focustab);
var urlHelper = _helper.GetUrlHelper(_accessor.ActionContext);
context.RedirectUri = UrlHelperExtensions.Action(urlHelper, "login", "account", routeValues);
return base.RedirectToLogin(context);
}
}

This allows me to modify the query string and returnUrl parameter on Redirect to Login requests. My requirement was to remove a specific query string value on first request to Login, and this allows me to meet that need.

It was pointed out in the comments that ActionContext is null in .net Core 3.1. I created a new .net core 3.1 project and this is the new code to make sure ActionContext is NOT null. Have not fully tested, just made sure the ActionContext was not null for inject IActionContextAccessor.

The main thing to remember here is that IActionContextAccessor works with the MVC pipeline. This means we would have to change the .net core 3.1 template to use MVC. CustomCookieAuthenticationEvents does not change.

New Startup.cs

public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(m =>
{
m.EnableEndpointRouting = false;
});
//register the IActionContextAccessor so that I can inject into my CustomCookieAuthenticationEvents constructor
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddScoped<CustomCookieAuthenticationEvents>();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(o =>
{
o.AccessDeniedPath = new PathString("/Error/AccessDenied");
o.LoginPath = new PathString("/Account/Login/");
o.Cookie.Path = "/";
o.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
o.Cookie.HttpOnly = true;
o.LogoutPath = new PathString("/Account/Logout/");
//This line here
o.EventsType = typeof(CustomCookieAuthenticationEvents);
});

}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();

//app.UseRouting();

app.UseAuthorization();

app.UseMvcWithDefaultRoute();

//app.UseEndpoints(endpoints =>
//{
// endpoints.MapControllerRoute(
// name: "default",
// pattern: "{controller=Home}/{action=Index}/{id?}");
//});
}


Related Topics



Leave a reply



Submit