asp.net - bearer - Autenticación Dotnet Core 2.0 esquemas múltiples cookies de identidad y jwt
jwt asp net core web api (4)
En dotnet core 1.1 asp, pude configurar y usar el middleware de identidad seguido del middleware jwt haciendo lo siguiente:
app.UseIdentity();
app.UseJwtBearerAuthentication(new JwtBearerOptions() {});
Esto ha cambiado ahora que implementamos el middleware con:
app.UseAuthentication();
La configuración de los ajustes se realiza a través de la sección Configurar servicios de Startup.cs.
Hay algunas referencias al uso de esquemas de autorización en la documentación de migración:
En proyectos 2.0, la autenticación se configura a través de servicios. Cada esquema de autenticación se registra en el método ConfigureServices de Startup.cs. El método UseIdentity se reemplaza con UseAuthentication.
Adicionalmente hay una referencia a:
Configuración de esquemas de autenticación predeterminados
En 1.x, las propiedades AutomaticAuthenticate y AutomaticChallenge se diseñaron en un solo esquema de autenticación. No había una buena manera de hacer cumplir esto.
En 2.0, estas dos propiedades se han eliminado como marcas en la instancia individual de AuthenticationOptions 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:
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 puede especificarse alternativamente dentro de sus atributos [Autorizar] o políticas de autorización individuales.
¿Todavía es posible en dotnet core 2.0 usar múltiples esquemas de autenticación? No puedo conseguir que la política respete la configuración de JWT (esquema "Portador"), y solo Identity está trabajando actualmente con ambos configurados. No puedo encontrar ninguna muestra de múltiples esquemas de autenticación.
Editar:
He releído la documentación y ahora entiendo que:
app.UseAuthentication()
Agrega autenticación automática contra un esquema predeterminado. Identity configura los esquemas predeterminados por ti.
He solucionado el problema con lo que parece ser un hack que trabaja contra las nuevas API haciendo lo siguiente en Startup.cs Configure:
app.UseAuthentication();
app.Use(async (context, next) =>
{
if (!context.User.Identity.IsAuthenticated)
{
var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
if (result?.Principal != null)
{
context.User = result.Principal;
}
}
await next.Invoke();
});
¿Es esta la forma correcta de hacer esto o debo utilizar el marco, DI e interfaces para implementaciones personalizadas de IAuthenticationSchemeProvider?
Editar - Más detalles de la implementación y dónde encontrarla.
La configuración de JWT se puede encontrar aquí, y estoy usando políticas para definir la autorización, que incluyen los esquemas de autenticación aceptados:
https://github.com/Arragro/ArragroCMS/blob/master/src/ArragroCMS.Management/Startup.cs
Todavía se implementa middleware personalizado. El controlador de Auth está aquí:
Utiliza las claves API generadas por la aplicación para obtener acceso de solo lectura a los datos. Puede encontrar la implementación de un controlador utilizando la política aquí:
Cambie la cadena de conexión de base de datos para que apunte a su servidor SQL y ejecute la aplicación. Migra la base de datos automáticamente y configura un usuario administrador ([email protected] - ArragroPassword1!). Luego vaya a la pestaña Configuración en la barra de menú y haga clic en "Configurar la configuración de la clave de API de solo lectura JWT" para obtener una clave. En cartero, obtenga un token jwt configurando una nueva pestaña y configurándola en POST con la siguiente dirección:
http://localhost:5000/api/auth/readonly-token
Suministre los encabezados: Content-Type: application / json
Suministrar el cuerpo
{
"apiKey": "the api token from the previous step"
}
Copie el token en la respuesta y luego use lo siguiente en el cartero:
http://localhost:5000/api/sitemap/flat
Authorization: "bearer - The token you received in the previous request"
Funcionará inicialmente debido al middleware personalizado. Comente el código mencionado anteriormente e inténtelo de nuevo y recibirá un 401.
Editar: la respuesta de @DonnyTian a continuación cubre mi solución en sus comentarios. El problema que estaba teniendo era establecer una política predeterminada en UseMvc, pero no proporcionar los esquemas:
services.AddMvc(config =>
{
var defaultPolicy = new AuthorizationPolicyBuilder(new[] { JwtBearerDefaults.AuthenticationScheme, IdentityConstants.ApplicationScheme })
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(defaultPolicy));
config.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
config.Filters.Add(new ValidateModelAttribute());
});
Siguiendo el consejo, esto funciona sin middleware personalizado.
Asp.Net Core 2.0 definitivamente soporta múltiples esquemas de autenticación. En lugar de un hacking con middleware de autenticación, puede intentar especificar el esquema en el atributo Authorize
:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
Lo intenté y funcionó bien. Suponiendo que haya agregado tanto Identity como JWT como se muestra a continuación:
services.AddIdentity<ApplicationUser, ApplicationRole>()
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
Dado que AddIdentity()
ya estableció la autenticación de cookies como el esquema predeterminado, debemos especificar el esquema en el atributo Authorize
de los controladores. Por ahora, no tengo idea de cómo sobrescribir el conjunto de esquemas predeterminado por AddIdentity()
, o quizás sea mejor que no lo hagamos.
Una solución alternativa es componer una nueva clase (puede llamarlo JwtAuthorize) que se deriva de Authorize
y tiene el Portador como el esquema predeterminado, por lo que no tiene que especificarlo cada vez.
ACTUALIZAR
¡Encontró la manera de anular el esquema de autenticación predeterminado de Identidad!
En lugar de debajo de la línea:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
Utilice la sobrecarga a continuación para establecer el esquema predeterminado:
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>....
ACTUALIZACIÓN 2 Como se mencionó en los comentarios, puede habilitar tanto la identidad como la autenticación JWT uniéndolas. [Authorize(AuthenticationSchemes = "Identity.Application" + "," + JwtBearerDefaults.AuthenticationScheme)]
Basado en lo que dice kevin rich aquí http://www.whoiskevinrich.com/configuring-asp-net-core-2-0-authentication
Pude establecer jwt como el método de autenticación predeterminado:
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultForbidScheme = JwtBearerDefaults.AuthenticationScheme;
})
Probé esto y pude eliminar (AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme) del atributo de autorización mencionado en la publicación de donnytian.
Sean Wildermuth tiene una publicación en el blog sobre la habilitación de cookies y jwt: https://wildermuth.com/2017/08/19/Two-AuthorizationSchemes-in-ASP-NET-Core-2
Él lo encadena así:
services.AddAuthentication()
.AddCookie(cfg => cfg.SlidingExpiration = true)
.AddJwtBearer(cfg =>
{
cfg.RequireHttpsMetadata = false;
cfg.SaveToken = true;
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = Configuration["Tokens:Issuer"],
ValidAudience = Configuration["Tokens:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"]))
};
});
Utilicé esta pregunta para resolver mi (similar) problema de combinar la autenticación de Identidad y del Portador en una aplicación web .Net Core 2.0. Es importante tener en cuenta que debe agregar el new[] { JwtBearerDefaults.AuthenticationScheme, IdentityConstants.ApplicationScheme
a la siguiente pieza de código:
services.AddMvc(config =>
{
var defaultPolicy = new AuthorizationPolicyBuilder(new[] { JwtBearerDefaults.AuthenticationScheme, IdentityConstants.ApplicationScheme })
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(defaultPolicy));
config.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
config.Filters.Add(new ValidateModelAttribute());
});
Y
Agregue la opción de autenticación predeterminada:
services.AddAuthentication(option =>
{
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>....
En mi solución inicial basada en esta pregunta, no me di cuenta de que ambos cambios en mi código eran necesarios. Espero poder ahorrarle a alguien las horas que desperdicié :)