JSON Web Token - Seguridad en servicios Web API de .NET Core
La seguridad en los servicios Web API, es un punto fundamental a la hora de implementar este tipo de soluciones en nuestros desarrollos sobre la plataforma .NET.
A partir de la versión 2.1 del Framework ASP.NET Core, Microsoft incluye por defecto un sistema de autenticación de usuarios para servicios Web API RESTful, basado en la tecnología JSON Web Tokens (JWT).
En este artículo veremos cómo crear desde cero un servicio Web API RESTful de .NET Core con seguridad basada en JSON Web Token, para posteriormente explicar con detalle, el proceso de autenticación de los usuarios en el servicio con el gestor de peticiones HTTP Postman.
Seguramente, si has decidido leer este artículo, es porque ya conoces la tecnología JSON Web Token (JWT en adelante), y lo que te interesa es saber cómo implementar en tus servicios Web API RESTful este sistema de autenticación de usuarios.
Es por esto que pasaremos directamente a desarrollar desde cero nuestro ejemplo de Web API RESTful con seguridad JWT en ASP.NET Core.
Nota: Existe infinidad de información en Internet acerca de JWT que puedes consultar si quieres conocer en profundidad el funcionamiento de este estándar, como por ejemplo este artículo de Wikipedia.
Creando nuestro Web API RESTful con Visual Studio
Para este ejemplo, utilizaremos Visual Studio 2017 con todas las actualizaciones necesarias para usar el SDK de .NET Core 2.2.
En primer lugar, crearemos un nuevo proyecto del tipo Aplicación Web ASP.NET Core, y seleccionaremos la plantilla API con plataforma de destino .NET Core y Framework ASP.NET Core 2.2.
Nota: En el caso de querer compilar la aplicación para Windows (IIS), pueden elegir como plataforma de destino .NET Framework (Fulll framework). Así mismo, también pueden utilizar el Framework ASP.NET Core 2.1 si así lo estimaran conveniente.
El Modelo de datos
Antes de crear nuestro Web API RESTful, debemos definir el Modelo de datos sobre el cual trabajaremos posteriormente.
Para esto, crearemos una nueva carpeta en el proyecto llamada Models
, y en su interior definiremos una nueva clase llamada Pais.cs
de la siguiente manera:
public class Pais
{
public Pais()
{
this.Id = Guid.NewGuid();
}
[Key]
public Guid Id { get; set; }
[Required]
[StringLength(50, MinimumLength = 3)]
public string Nombre { get; set; }
[Required]
public int Habitantes { get; set; }
}
El Controlador de API
En este momento, ya podremos crear la clase controladora para nuestro Web API RESTful.
Pera esto, nos situaremos en la carpeta Controllers
del proyecto, y con el botón derecho del ratón accederemos al menú contextual (opción Agregar > Controlador ...) para crear un nuevo Controlador del tipo Controlador de API con acciones que usan Entity Framework.
Seleccionando esta plantilla, Visual Studio creará por nosotros (Scaffolding) un Controlador API RESTful con Acciones CRUD que usan Entity Framework.
Lo interesante de esta opción, es que simplemente indicándole un Modelo de datos y el nombre de la clase que actuará como Contexto de datos, Visual Studio instalará por nosotros los paquetes NuGet de Entity Framework Core necesarios para la aplicación, y creará un Contexto de datos y cadena de conexión hacia una Base de Datos SQL Server del tipo (localdb)\\mssqllocaldb
que posteriormente crearemos desde Entity Famework (Code First).
Si todo ha ido bien, en este punto ya tendremos creado nuestro Controlador API (PaisController.cs
) con Acciones CRUD sobre el Modelo de datos Pais.cs
:
[Route("api/[controller]")]
[ApiController]
public class PaisController : ControllerBase
{
private readonly ApplicationDbContext _context;
public PaisController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/Pais
[HttpGet]
public async Task<ActionResult<IEnumerable<Pais>>> GetPais()
{
return await _context.Pais.ToListAsync();
}
// GET: api/Pais/5
[HttpGet("{id}")]
public async Task<ActionResult<Pais>> GetPais(Guid id)
{
var pais = await _context.Pais.FindAsync(id);
if (pais == null)
{
return NotFound();
}
return pais;
}
// PUT: api/Pais/5
[HttpPut("{id}")]
public async Task<IActionResult> PutPais(Guid id, Pais pais)
{
if (id != pais.Id)
{
return BadRequest();
}
_context.Entry(pais).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!PaisExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return NoContent();
}
// POST: api/Pais
[HttpPost]
public async Task<ActionResult<Pais>> PostPais(Pais pais)
{
_context.Pais.Add(pais);
await _context.SaveChangesAsync();
return CreatedAtAction("GetPais", new { id = pais.Id }, pais);
}
// DELETE: api/Pais/5
[HttpDelete("{id}")]
public async Task<ActionResult<Pais>> DeletePais(Guid id)
{
var pais = await _context.Pais.FindAsync(id);
if (pais == null)
{
return NotFound();
}
_context.Pais.Remove(pais);
await _context.SaveChangesAsync();
return pais;
}
private bool PaisExists(Guid id)
{
return _context.Pais.Any(e => e.Id == id);
}
}
Así como nuestro Contexto de datos de Entity Framework Core ApplicationDbContext.cs
.
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext (DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Pais> Pais { get; set; }
}
Entity Framework Core y la Base de Datos
Durante el proceso de creación del Controlador API PaisController.cs
, Visual Studio ha generado por nosotros una cadena de conexión en el archivo de configuración appsettings.json
con la siguiente estructura:
"ConnectionStrings": {
"ApplicationDbContext": "Server=(localdb)\\mssqllocaldb;
Database=ApplicationDbContext-2dfbdd2b-470c-4bd4-99fe-9b1184c2e631;
Trusted_Connection=True;
MultipleActiveResultSets=true"
}
También ha configurado como servicio el Contexto de datos ApplicationDbContext
en la clase Startup.cs
. Esto es necesario, para poder "inyectar" el Contexto de datos en el Controlador API mediante Inyección de Dependencias.
...
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("ApplicationDbContext")));
}
...
Llegados a este punto, solo faltaría crear nuestra Base de Datos y comenzar a implementar la seguridad JWT, pero antes, crearemos una serie de datos de prueba que serán insertados en la tabla de Países a la hora de crear la base de datos.
Esto lo haremos desde el método OnModelCreating
del Contexto de datos ApplicationDbContext
de la siguiente manera:
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext (DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Pais> Pais { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Pais>().HasData(
new Pais { Nombre = "España", Habitantes = 46000000 },
new Pais { Nombre = "Alemania", Habitantes = 83000000 },
new Pais { Nombre = "Francia", Habitantes = 65000000 },
new Pais { Nombre = "Italia", Habitantes = 61000000 }
);
}
}
Ahora ya podemos crear nuestra base de datos, y esto lo haremos a través de Migraciones de Entity Framework Core (Code First).
En primer lugar abriremos la consola de administración de paquetes NuGet (Herramientas > Administrador de paquetes NuGet > Consola del Administrador de paquetes), y crearemos una Migración inicial de la siguiente manera:
PM> Add-Migration MigracionInicial
Y por último, aplicaremos los cambios:
PM> Update-Database
Si todo ha ido bien, ya tendremos creada la base de datos y la tabla de países con los datos de prueba.
Para probar el correcto funcionamiento del Web API, podemos realizar una petición GET desde nuestro explorador (/api/pais), obteniendo el siguiente resultado:
Configurando la seguridad con JWT
Antes de comenzar a configurar JWT, debemos proteger nuestro Web API de accesos no autorizados.
Para ello, "decoraremos" las Acciones del Controlador que requieran seguridad con el atributo [Authorize]
. Esto hará que de momento, las peticiones dirigidas a los elementos afectados (Acciones) retornen un HTTP 401 Unauthorized (acceso no autorizado).
...
// GET: api/Pais
[HttpGet]
[Authorize] // SOLO USUARIOS AUTENTICADOS
public async Task<ActionResult<IEnumerable<Pais>>> GetPais()
{
return await _context.Pais.ToListAsync();
}
...
Los parámetros de configuración JWT
En el archivo de configuración appsettings.json
, definiremos una serie de parámetros básicos que posteriormente serán utilizados para generar nuestro Token.
Issuer: Debe indicar quien es un emisor válido para el Token. Normalmente indicaremos el Dominio desde el cual se emite el Token.
Audience: Debe indicar la audiencia o destinatario a los que se dirige el Token. En nuestro caso indicaremos la Url de nuestro Web API.
ClaveSecreta: Obviamente es el parámetro de configuración más importante, ya que será la Clave que utilizaremos tanto para firmar digitalmente el Token al enviarlo, como para comprobar la validez de la firma al recibirlo.
{
...
"JWT": {
"ClaveSecreta": "OLAh6Yh5KwNFvOqgltw7",
"Issuer": "www.rafaelacosta.net",
"Audience": "www.rafaelacosta.net/api/miwebapi"
}
}
Creando el servicio de autenticación JWT
En el método ConfigureServices()
del archivo Startup.cs
de la aplicación, añadiremos los servicios de autenticación de ASP.NET Core (services.AddAuthentication()
) con la configuración específica para JWT.
public void ConfigureServices(IServiceCollection services)
{
// CONFIGURACIÓN DEL SERVICIO DE AUTENTICACIÓN JWT
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["JWT:Issuer"],
ValidAudience = Configuration["JWT:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(Configuration["JWT:ClaveSecreta"])
)
};
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("ApplicationDbContext")));
}
Una vez configurado el servicio de autenticación JWT, debemos añadir el Middleware de autenticación de ASP.NET Core (app.UseAuthentication()
) al Pipeline de la aplicación para que vigile las peticiones entrantes.
Esto lo haremos en el método Configure()
del archivo Startup.cs
de la aplicación.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseHsts();
app.UseHttpsRedirection();
// AÑADIMOS EL MIDDLEWARE DE AUTENTICACIÓN
// DE USUARIOS AL PIPELINE DE ASP.NET CORE
app.UseAuthentication();
app.UseMvc();
}
Generando el Token de autenticación con JWT
Llegados a este punto, ya podemos comenzar a implementar el sistema de generación de Tokens JWT, pero antes, crearemos una clase de Modelo llamada UsuarioInfo.cs
, la cual representará la información que identificará de manera única a los usuarios autenticados. Esta clase la utilizaremos posteriormente para construir el Payload de nuestros Tokens.
public class UsuarioInfo
{
public Guid Id { get; set; }
public string Nombre { get; set; }
public string Apellidos { get; set; }
public string Email { get; set; }
public string Rol { get; set; }
}
También necesitamos crear una clase de Modelo UsuarioLogin.cs
, que represente las credenciales de acceso de un usuario determinado. En nuestro caso definiremos las propiedades Usuario y Password.
public class UsuarioLogin
{
public string Usuario { get; set; }
public string Password { get; set; }
}
Por último crearemos un nuevo Controlador de API (LoginController.cs
), cuyo cometido será identificar mediante usuario y contraseña (UsuarioLogin.cs
) a los potenciales clientes de nuestro Web API, además de generar un Token válido que posteriormente será enviado de vuelta a quien lo solicitó.
[Route("api/[controller]")]
[ApiController]
public class LoginController : ControllerBase
{
private readonly IConfiguration configuration;
// TRAEMOS EL OBJETO DE CONFIGURACIÓN (appsettings.json)
// MEDIANTE INYECCIÓN DE DEPENDENCIAS.
public LoginController(IConfiguration configuration)
{
this.configuration = configuration;
}
// POST: api/Login
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login(UsuarioLogin usuarioLogin)
{
var _userInfo = await AutenticarUsuarioAsync(usuarioLogin.Usuario, usuarioLogin.Password);
if (_userInfo != null)
{
return Ok(new { token = GenerarTokenJWT(_userInfo) });
}
else
{
return Unauthorized();
}
}
// COMPROBAMOS SI EL USUARIO EXISTE EN LA BASE DE DATOS
private async Task<UsuarioInfo> AutenticarUsuarioAsync(string usuario, string password)
{
// AQUÍ LA LÓGICA DE AUTENTICACIÓN //
// Supondremos que el Usuario existe en la Base de Datos.
// Retornamos un objeto del tipo UsuarioInfo, con toda
// la información del usuario necesaria para el Token.
return new UsuarioInfo()
{
// Id del Usuario en el Sistema de Información (BD)
Id = new Guid("B5D233F0-6EC2-4950-8CD7-F44D16EC878F"),
Nombre = "Nombre Usuario",
Apellidos = "Apellidos Usuario",
Email = "email.usuario@dominio.com",
Rol = "Administrador"
};
// Supondremos que el Usuario NO existe en la Base de Datos.
// Retornamos NULL.
//return null;
}
// GENERAMOS EL TOKEN CON LA INFORMACIÓN DEL USUARIO
private string GenerarTokenJWT(UsuarioInfo usuarioInfo)
{
// CREAMOS EL HEADER //
var _symmetricSecurityKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(configuration["JWT:ClaveSecreta"])
);
var _signingCredentials = new SigningCredentials(
_symmetricSecurityKey, SecurityAlgorithms.HmacSha256
);
var _Header = new JwtHeader(_signingCredentials);
// CREAMOS LOS CLAIMS //
var _Claims = new[] {
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.NameId, usuarioInfo.Id.ToString()),
new Claim("nombre", usuarioInfo.Nombre),
new Claim("apellidos", usuarioInfo.Apellidos),
new Claim(JwtRegisteredClaimNames.Email, usuarioInfo.Email),
new Claim(ClaimTypes.Role, usuarioInfo.Rol)
};
// CREAMOS EL PAYLOAD //
var _Payload = new JwtPayload(
issuer: configuration["JWT:Issuer"],
audience: configuration["JWT:Audience"],
claims: _Claims,
notBefore: DateTime.UtcNow,
// Exipra a la 24 horas.
expires: DateTime.UtcNow.AddHours(24)
);
// GENERAMOS EL TOKEN //
var _Token = new JwtSecurityToken(
_Header,
_Payload
);
return new JwtSecurityTokenHandler().WriteToken(_Token);
}
}
Una vez que el usuario autenticado haya recibido el Token de acceso, ya podrá acceder con total seguridad a aquellas Acciones de nuestro Web API que hayan sido protegidas con el atributo [Authorize]
.
Este Token recibido, nos identificará como usuario autenticado en las sucesivas peticiones que realicemos al servicio Web API, sin necesidad de volvernos a validar en el sistema de información. Simplemente debemos indicar en la cabecera (Header) de las peticiones HTTP al Web API, un encabezado Authorization:
del tipo bearer
con el valor del Token obtenido.
Comprobando el sistema de seguridad JWT con Postman
Una vez implementada la seguridad JWT sobre nuestro servicio Web API de ASP.NET Core, comprobaremos cómo funciona el proceso de autenticación de usuarios, utilizando la herramienta de "testeo" de APIs REST Postman.
Cómo obtener el Token de acceso
Si en este momento del desarrollo realizáramos desde Postman una petición del tipo GET: api/Pais
a nuestro servicio Web API, obtendríamos una respuesta HTTP 401 Unauthorized.
Por lo tanto, y como requisito inicial, debemos solicitar un Token JWT válido accediendo al recurso POST: api/Login
.
Esto lo haremos enviando en el cuerpo de la petición (Body) un objeto JSON del tipo UsuarioLogin
, con un usuario y contraseña válidos en nuestro sistema de información. Si todo ha funcionado correctamente, recibiremos en el cuerpo de la respuesta nuestro Token de acceso JWT.
Realizando una petición GET al Web API
En este momento ya estamos en disposición de realizar cualquier petición a nuestro servicio Web API PaisController
, siempre y cuando indiquemos en la cabecera (Head) de dichas peticiones, nuestro Token de acceso JWT obtenido anteriormente.
Esto lo haremos mediante Postman de la siguiente manera:
En primer lugar crearemos una nueva petición del tipo GET al recurso GET: api/Pais
.
Seguidamente, accederemos a la pestaña Authorization y seleccionaremos el tipo Bearer Token.
A continuación copiaremos y pegaremos el Token de acceso en el campo indicado y pulsaremos el botón Preview Request.
Esto hará que en la cabecera de la petición se cree un encabezado Authorization
de tipo Bearer
con el valor del Token de acceso.
GET /api/pais HTTP/1.1
Host: localhost:5001
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlYzk2MzVmNS04ZTEzLTQ4YTMtOGE5NC1lYmE3NDZiMDdlZjkiLCJuYW1laWQiOiJiNWQyMzNmMC02ZWMyLTQ5NTAtOGNkNy1mNDRkMTZlYzg3OGYiLCJub21icmUiOiJOb21icmUgVXN1YXJpbyIsImFwZWxsaWRvcyI6IkFwZWxsaWRvcyBVc3VhcmlvIiwiZW1haWwiOiJlbWFpbC51c3VhcmlvQGRvbWluaW8uY29tIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiQWRtaW5pc3RyYWRvciIsIm5iZiI6MTU1OTUxNjI0NCwiZXhwIjoxNTU5NjAyNjQ0LCJpc3MiOiJ3d3cucmFmYWVsYWNvc3RhLm5ldCIsImF1ZCI6Ind3dy5yYWZhZWxhY29zdGEubmV0L2FwaS9taXdlYmFwaSJ9.gokqwD7dcKwZUFVcvAcNc52WyUrVTTQjavrp0uBbESA
Por ultimo enviaremos la petición al servidor, y veremos como recibimos una respuesta HTTP 200 Ok, con el contenido de los registros de la base de datos en formato JSON.
Importante: Los Tokens JWT caducan, esto quiere decir que a la hora de generarlos, podemos indicar un tiempo de validez mediante el parámetro
expires:
de la claseJwtPayload()
. Por esta razón debemos estar atentos a las respuestas HTTP 401 (acceso no autorizado) del Web API, para volver a solicitar un nuevo Token si fuera necesario.
Enviando una petición POST al Web API
En el caso de una petición POST, los pasos iniciales del proceso serían los mismos.
En primer lugar solicitaríamos el Token de acceso, y lo añadiríamos a la cabecera e la petición mediante el encabezado Authorization
.
A continuación, crearíamos en el cuerpo (Body) de la petición, el nuevo objeto JSON del tipo Pais.cs
que queremos enviar al servidor para ser insertado en la base de datos.
Por último, enviaremos la petición al servidor, y veremos como recibimos una respuesta HTTP 201 Created con el nuevo objeto creado en la base de datos.
Nuevo comentario
Comentarios
excelente información, podrias hacer un tutorial sobre como refrescar el token??
Muy bueno el documento de verdad.
Un aporte, me di cuenta que el tiempo de expiración del token no estaba funcionando.
Lo solucione de la siguiente forma, le agregue al objeto TokenValidationParameters en el startup el siguiente parametro ClockSkew = TimeSpan.Zero
Ej:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(configuration["JWT:ClaveSecreta"])
),
ClockSkew = TimeSpan.Zero
};
});
Hola muchas gracias, cómo hago el llamado desde una aplicación ASPNET CORE y adiciono los headers?
Es posible que ASPNET CORE almacene el token y automáticamente lo coloque en cada Request?
Hola buen aporte, excelente, con una consulta cuando el usuario se autentica de forma satisfactoria, como puedo retornar la información de "UsuarioInfo" por ejemplo retornar Id, Nombre, Apellido, Email y así mismo el token
El mejor post que he encontrado en mucho tiempo
@Aquario:
Hola Aquario, Para aplicar seguridad basada en Tokens en Servicios Web SOAP ASMX, puedes consultar los siguientes artículos de este blog:
Seguridad en Servicios Web SOAP ASP.NET - Token de acceso (I)
Seguridad en Servicios Web SOAP ASP.NET - Token de acceso (II)
Hola, interesante articulo. Como seria posible realizar la api con .asmx o web api con webforms ?? y el acceso con server sql ?
MUY BUEN TRABAJO!!
EXCELENTE TRABAJO TESTEADO PROBADO FUNCIONANDO..perfectamente te ganaste mi aprecio y un 100 de por medio...
Saludos
Hola! Excelente artículo!!
Pero, o no entiendo el mecanismo o algo estoy haciendo mal.
Cito: Audience: Debe indicar la audiencia o destinatario a los que se dirige el Token.
Si configuro lo siguiente:
ValidateAudience = true,
"Audience": "www.rafaelacosta.net"
Y en el Controlador agrego: [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
Y trato de consumir la API desde una url diferente de www.rafaelacosta.net, entiendo que debería NO permitirme consumirla, pero eso no está sucediendo.
Qué estoy haciendo mal?
Saludos y muchas gracias anticipadas!
Excelente, muchísimas gracias.
@Camilo Ramirez:
Lee con detenimiento estos tres artículos, y seguro que encontrarás tu mismo la respuesta a tu pregunta:
Cómo crear un cliente C# para un Web API de ASP.NET Core (I)
Cómo crear un cliente C# para un Web API de ASP.NET Core (II)
Cómo crear un cliente C# para un Web API de ASP.NET Core (III)
Pregunta... como se puede consumir desde c# servicio con metodo get y enviando el token
@Jeanpierre:
Gracias por tu comentario Jeanpierre.
Efectivamente, los Claims sirven para almacenar información adicional del Usuario, que irá codificada en el propio Token JWT.
Una vez obtengas el Token de acceso, podrás decodificarlo para obtener la información del usuario que lo solicitó. El proceso de decodificación lo puedes ver en el artículo Cómo crear un cliente C# para un Web API de ASP.NET Core (II).
Felicitaciones bien explicado, una consulta al hacer POST como pueda obtener el ID de usuario que esta en el CLAIMS, esta para insertar en mi log de auditoria y saber que usuario registro, pasa que no quiero enviarlo el el cuerpo del JSON.
Yo mismo jjjj.
Olvida mi último comentario, ya me di cuenta que estaba haciendo mal :(
Gracias por el excelente artículo.
Excelente artículo. Solo tengo un problema y espero puedas ayudarme a resolverlo. Al probar con POSTMAN no me devuelve el token, sino el error "415 Unsupported Media Type". ¿Sabes por qué pasa esto?
Saludos y gracias
@Jesus Garcia:
Gracias por tu comentario.
Compartir los artículos en redes sociales y hacer click de vez en cuando en los banners de publicidad, es fundamental para que este Blog siga ofreciendo publicaciones de calidad y en español.
Excelente Tutorial
Buenísimo. Conoces la forma de implementar esto con RefreshToken?
@Elizalde Bardales:
Muchas gracias por tu aportación.
Para proyectos generados con la versión de visual studio 2019, agregar en el controlador la autorización así:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
Gracias por este hermoso tutorial.
loco sos un genio me salvaste la vida
!!!!!
@Julián:
La clave secreta puede ser la que tu quieras. En este ejemplo yo he utilizado una clave auto-generada por una de estas aplicaciones de Internet que te generan claves aleatorias fuertes. https://passwordsgenerator.net/
Muy buen ejemplo de implementacion de JWT amigo, una pregunta, la clave secreta como se genera?, puede ser cualquier parametro o valor ?
@Jairo M:
Hoia, has probado a hacer lo que te dice el error?.
En
ConfigureServices
define el Servicio MVC de esta manera:Buenos dias amigo he tratado de hacer tu ejemplo con el tutorial que me suministras pero siempre me da un error exactamente aqui: app.UseMvc();
System.InvalidOperationException
HResult=0x80131509
Mensaje = Endpoint Routing does not support 'IApplicationBuilder.UseMvc(...)'. To use 'IApplicationBuilder.UseMvc' set 'MvcOptions.EnableEndpointRouting = false' inside 'ConfigureServices(...).
Origen = Microsoft.AspNetCore.Mvc.Core
Seguimiento de la pila:
at Microsoft.AspNetCore.Builder.MvcApplicationBuilderExtensions.UseMvc(IApplicationBuilder app, Action`1 configureRoutes)
at Microsoft.AspNetCore.Builder.MvcApplicationBuilderExtensions.UseMvc(IApplicationBuilder app)
at WebApplication11.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in I:\w8\repos\WebApplication11\WebApplication11\Startup.cs:line 76
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass13_0.<UseStartup>b__2(IApplicationBuilder app)
at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Server.IIS.Core.IISServerSetupFilter.<>c__DisplayClass2_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.<StartAsync>d__31.MoveNext()
no se si es por que mi version es 3.1?? no tengo idea ya que hacer
Genial, me sirvió mucho, muchas gracias.
Gracias!!!!
@José:
Gracias por tu comentario. Compartir los artículos en redes sociales y foros de programación, es fundamental para que este Blog siga ofreciendo publicaciones de calidad y en español.
Tus aportes son muy importantes
MUY BUEN TRABAJO .