authentication - net - web api rest c#
ASP.Net Core: no hay redireccionamiento en el error de autenticación de API (3)
Actualizar ASP.NET Core 2.x
La autorización cambió un poco en ASP.NET Core 2.0. La respuesta a continuación solo es válida para ASP.NET Core 1.x. Para ASP.NET Core 2.0, consulte esta answer y este anuncio de GitHub .
ASP.NET Core 1.x
Lo que parece haber olvidado es que app.UseIdentity()
también registra el middleware de cookies .
var options = app.ApplicationServices.GetRequiredService<IOptions<IdentityOptions>>().Value;
app.UseCookieAuthentication(options.Cookies.ExternalCookie);
app.UseCookieAuthentication(options.Cookies.TwoFactorRememberMeCookie);
app.UseCookieAuthentication(options.Cookies.TwoFactorUserIdCookie);
app.UseCookieAuthentication(options.Cookies.ApplicationCookie);
y ASP.NET Core Identity establece el AutomaticChallange
en true
para el middleware de cookie ( ApplicationCookie
) ( ver fuente ). Por lo tanto, la redirección a /Account/Login?ReturnUrl
. Necesitará deshabilitar esta opción en Identidad.
services.AddIdentity(options =>
{
options.Cookies.ApplicationCookie.AutomaticChallenge = false;
});
Si realmente desea tener Identity''s Auth (inicio de sesión en la página web) y JWT, deberá registrar los middlewares según la url. Así que, por ejemplo, app.UseIdentity()
solo se registra para urls que no son de API y el middleware Jwt solo se registra para urls que comienzan con /api
.
Puedes hacer eso con .MapWhen
( docs ).
app.MapWhen(context => !context.Request.Path.StartsWith("/api"), branch =>
{
branch.UseIdentity();
});
Ahora se branch.UseIdentity()
, para URL que no comiencen con /api
, que generalmente son sus vistas de MVC donde se desea redirigir a /Account/Login
.
En mi proyecto ASP.NET Core obtuve algunos controladores de API con jwt-autorización como este:
[Route("api/v1/[controller]")]
public class MyController : Controller
{
[HttpGet("[action]")]
[Authorize(Policy = MyPolicy)]
public JsonResult FetchAll()
{
}
}
Cuando la autorización para acceder a la acción FetchAll () falla, quiero HttpStatusCode.Forbidden como respuesta. En su lugar, ¿Mvc realiza un cambio de ruta a la cuenta / inicio de sesión? ReturnUrl = [...]
Intenté capturar los Eventos de redirección y devolver Prohibido / No autorizado anulando los Eventos de cookies sin ningún resultado:
app.UseIdentity();
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = TokenController.DummyKey,
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(0)
};
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = tokenValidationParameters,
});
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AutomaticAuthenticate = false,
AutomaticChallenge = false,
AuthenticationScheme = "BsCookie",
CookieName = "access_token",
TicketDataFormat = new CustomJwtDataFormat(SecurityAlgorithms.HmacSha256, tokenValidationParameters),
Events = new CookieAuthenticationEvents
{
OnRedirectToLogin = context =>
{
if (context.Request.Path.StartsWithSegments("/api") && context.Response.StatusCode == (int)HttpStatusCode.OK)
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
else
context.Response.Redirect(context.RedirectUri);
return Task.FromResult(0);
},
OnRedirectToAccessDenied = context =>
{
if (context.Request.Path.StartsWithSegments("/api") && context.Response.StatusCode == (int)HttpStatusCode.OK)
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
else
context.Response.Redirect(context.RedirectUri);
return Task.FromResult(0);
}
},
});
Ambos eventos nunca se llaman y la salida de Visual Studio muestra que Fetchall Fails y en su lugar se devolverán Account / Login:
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:6460/api/v1/Lehrer/GetAll application/json
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: Successfully validated the token.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: HttpContext.User merged via AutomaticAuthentication from authenticationScheme: Bearer.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed for user: (null).
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter ''Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter''.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerMiddleware:Information: AuthenticationScheme: Bearer was forbidden.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware:Information: AuthenticationScheme: Identity.Application was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action Sam.Learning2.Controllers.LehrerController.GetAll (Sam.Learning2) in 49.7114ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 121.6106ms 302
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:6460/Account/Login?ReturnUrl=%2Fapi%2Fv1%2FLehrer%2FGetAll
Quiero que mis API devuelvan 401/403 en lugar de redirigir al inicio de sesión. ¿Cómo logro esto cuando el código anterior no funciona?
La pila de API web de Microsoft está configurada para hacer esto de manera inmediata. La solución está en el extremo del cliente.
Agregue este encabezado a la solicitud del cliente:
''X-Requested-With'': ''XMLHttpRequest''
Web api busca ese encabezado. Cuando está presente, devuelve un 401 si la solicitud no está autenticada. Cuando el encabezado está ausente, devuelve la redirección a la página de inicio de sesión.
Consulte este https://github.com/aspnet/Security/issues/1394#issuecomment-326445124
Creo que solo necesita el código más complejo en los eventos de cookies si no puede modificar el cliente.
Solo uso Barry Dorrans Asp Net Authorization Workshop
en ConfigureServices
acabo de agregar services.AddAuthorization();
.
y en Configure
agregue este código:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = "Cookie",
LoginPath = new PathString("/Account/Login/"),
AccessDeniedPath = new PathString("/Account/Forbidden/"),
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Events = new CookieAuthenticationEvents()
{
OnRedirectToLogin = (ctx) =>
{
if (ctx.Request.Path.StartsWithSegments("/api") && ctx.Response.StatusCode == 200)
{
ctx.Response.StatusCode = 401;
}
else
ctx.Response.Redirect(ctx.RedirectUri);
return Task.CompletedTask;
},
OnRedirectToAccessDenied = (ctx) =>
{
if (ctx.Request.Path.StartsWithSegments("/api") && ctx.Response.StatusCode == 200)
{
ctx.Response.StatusCode = 403;
}
else
{
ctx.Response.Redirect(ctx.RedirectUri);
}
return Task.CompletedTask;
}
}
}
En el enrutamiento de Mvc a Cuenta / Iniciar sesión? ReturnUrl = [...] y en API obtendrá 401 o 403.