c# - ASP.NET Core 2.0 deshabilitar desafío automático
authentication asp.net-core (8)
Como se señaló en algunas de las otras respuestas, ya no hay una configuración para desactivar el desafío automático con autenticación de cookies.
La solución es anular
OnRedirectToLogin
:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Events.OnRedirectToLogin = context =>
{
context.Response.Headers["Location"] = context.RedirectUri;
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
});
Esto puede cambiar en el futuro: https://github.com/aspnet/Security/issues/1394
Después de actualizar mi proyecto ASP.NET Core a 2.0, los intentos de acceder a puntos finales protegidos ya no devuelven 401, sino que redirigen a un punto final (no existente) en un intento de permitir que el usuario se autentique.
El comportamiento deseado es que la aplicación simplemente devuelva un 401. Anteriormente, establecería
AutomaticChallenge = false
al configurar la autenticación, pero de acuerdo con
este artículo,
la configuración ya no es relevante (de hecho, ya no existe).
Mi autenticación está configurada así:
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();
});
Configurar ():
app.UseAuthentication();
¿Cómo puedo desactivar el desafío automático para que la aplicación devuelva 401 cuando el usuario no está autenticado?
De acuerdo con this artículo:
En 1.x, las propiedades AutomaticAuthenticate y AutomaticChallenge estaban destinadas a establecerse en un único esquema de autenticación. No había una buena manera de hacer cumplir esto.
En 2.0, estas dos propiedades se han eliminado como indicadores en la instancia de AuthenticationOptions individual y se han movido a la clase base AuthenticationOptions. Las propiedades se pueden configurar en la llamada al método AddAuthentication dentro del método ConfigureServices de Startup.cs
services.AddAuthentication(options => {
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});
Alternativamente, use una versión sobrecargada del método AddAuthentication para establecer más de una propiedad. En el siguiente ejemplo de método sobrecargado, el esquema predeterminado se establece en CookieAuthenticationDefaults.AuthenticationScheme. El esquema de autenticación se puede especificar alternativamente dentro de sus atributos individuales [Autorizar] o políticas de autorización.
services.ConfigureApplicationCookie(options => {
options.Events.OnRedirectToLogin = context => {
context.Response.Headers["Location"] = context.RedirectUri;
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
});
Defina un esquema predeterminado en 2.0 si una de las siguientes condiciones es verdadera:
- Desea que el usuario inicie sesión automáticamente
- Utiliza el atributo [Autorizar] o las políticas de autorización sin especificar esquemas
Una excepción a esta regla es el método AddIdentity . Este método agrega cookies para usted y establece los esquemas predeterminados de autenticación y desafío para la cookie de la aplicación IdentityConstants.ApplicationScheme . Además, establece el esquema de inicio de sesión predeterminado en la cookie externa IdentityConstants.ExternalScheme .
Espero que esto te ayude.
De manera similar a @Serverin, la configuración de OnRedirectToLogin de la cookie de la aplicación funcionó, pero debe hacerse en la declaración siguiente services.AddIdentity en Startup.cs: ConfigureServices:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
Descubrí que en la mayoría de los casos la solución es anular
OnRedirectToLogin
Pero en mi aplicación estaba usando múltiples políticas de autenticación y la anulación de
OnRedirectToLogin
no funcionó para mí.
La solución en mi caso fue agregar un middleware simple para redirigir la solicitud entrante.
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;
}
}
});
Después de investigar un poco, descubrí que podemos tratar este problema a través del siguiente enfoque:
Podemos agregar dos esquemas de autenticación, Identity y JWT; y use el esquema de identidad para la autenticación y use el esquema JWT para el desafío, JWT no redirigirá a ninguna ruta de inicio de sesión durante el desafío.
services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>();
services.AddAuthentication((cfg =>
{
cfg.DefaultScheme = IdentityConstants.ApplicationScheme;
cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})).AddJwtBearer();
Este es el código fuente de 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;
};
Puede agregar el encabezado "X-Requested-With: XMLHttpRequest" a la solicitud mientras realiza llamadas API desde su cliente.
No estoy seguro de cómo generar el error 401, sin embargo, si usa el:
o.AccessDeniedPath = "{path to invalid}";
Esto te permitirá redirigir a algún lugar cuando el desafío ha fallado.
Otra forma de hacer esto que es más amigable con DI / testing es usar
AuthenticationSchemeOptions.EventsType
(otra respuesta
apunta aquí
).
Esto le permitirá incorporar otros componentes al proceso de resolución.
Aquí hay un ejemplo que incluye el registro y la resolución que detiene la redirección predeterminada para iniciar sesión en una solicitud no autenticada, y en su lugar solo regresa con un
401
duro.
También tiene una ranura para cualquier otra dependencia que pueda necesitar conocer sobre solicitudes no autenticadas.
En
Startup.cs
:
services
.AddAuthentication("MyAuthScheme")
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.EventsType = typeof(MyEventsWrapper);
};
...
services.AddTransient<MyEventsWrapper>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Luego, en
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);
}
}