1: Importar el paquete NuGet Microsoft.AspNetCore.Authentication.JwtBearer
2: Configuración de parámetros JWT
3: Configuración en Startup
1 public void ConfigureServices(IServiceCollection services){
2 #region Configuración de Autenticación JWT
3 services
4 .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
5 .AddJwtBearer(options => {
6 var configData = AppConfigurationHelper.LoadConfiguration();
7 options.TokenValidationParameters = new TokenValidationParameters
8 {
9 ValidIssuer = configData.Issuer,
10 ValidAudience = config.Audience,
11 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.SecretKey)),
12 ClockSkew = TimeSpan.Zero
13 };
14 });
15 #endregion
16 }
17
18 // Asegurarse de que está antes de AddMvc()
19 services.AddMvc();
20
21 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
22 {
23 app.UseAuthentication();
24 app.UseAuthorization();
25 }
Ver código4: Utilizar atributos en Controladores y Acciones
Se puede utilizar el atributo [Authorize] individualmente en cada Action. Para omitir la autenticación, utiliza el atributo [AllowAnonymous]. Ambos atributos se encuentran en el siguiente namespace: using Microsoft.AspNetCore.Authorization;
5: Implementación del inicio de sesión y generación de tokens
Después de un inicio de sesión exitoso, el backend debe devolver el token generado. Puedes probarlo con Postman o en el sitio web oficial JWT.io.
6: Anviar solicitudes al backend con el token
Ejemplo de solicitud GET: ://localhost:5000/usuario/login Cabecera (Header) Authorization Bearer qweTdfdsfsJhdsfd0.fdsfdsgfdsewDDQDD.fdsfdsg***
7: Código de ejemplo para acciones
1 [HttpPost, Route("Login")]
2 public ApiResponse Login(usuario usuario)
3 {
4 ApiResponse respuesta = new ApiResponse();
5 try
6 {
7 string tokenString = AutenticacionJwtHelper.GenerarToken(usuario);
8 respuesta.data = tokenString;
9 respuesta.codigo = EstadoExito.Ok;
10 respuesta.mensaje = "Token generado exitosamente!";
11 }
12 catch (Exception ex)
13 {
14 respuesta.mensaje = "Error en la autenticación: " + ex.Message;
15 }
16 return respuesta;
17 }
18
19
20 [HttpPost, Route("verificarAutenticacion")]
21 [Authorize]
22 [AllowAnonymous] // Para omitir autenticación cuando sea necesario
23 public ApiResponse verificarAutenticacion(string tokenAcceso)
24 {
25 ApiResponse respuesta = new ApiResponse();
26 try
27 {
28 var datosToken = AutenticacionJwtHelper.DecodificarToken(tokenAcceso);
29 respuesta.data = datosToken;
30 respuesta.codigo = EstadoExito.Ok;
31 respuesta.mensaje = "Verificación exitosa!";
32 }
33 catch (Exception ex)
34 {
35 respuesta.mensaje = "Error en la verificación: " + ex.Message;
36 }
37 return respuesta;
38 }
Ver código8: Implementación completa del helper JWT
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Threading.Tasks;
5 namespace ProyectoWeb.Utilidades
6 {
7 using Microsoft.AspNetCore.Http;
8 using Microsoft.IdentityModel.Tokens;
9 using System.IdentityModel.Tokens.Jwt;
10 using System.Security.Claims;
11 using System.Text;
12 using ProyectoWeb.Modelos;
13
14 /// <summary>
15 /// Helper para la generación y validación de JWT tokens
16 /// </summary>
17 public class AutenticacionJwtHelper
18 {
19 /// <summary>
20 /// Genera un token JWT
21 /// </summary>
22 /// <param name="usuario">Datos del usuario</param>
23 /// <returns>Token JWT como string</returns>
24 public static string GenerarToken(usuario usuario)
25 {
26 var config = ConfiguracionApp.ObtenerConfiguracion();
27 string emisor = config.Emisor;
28 string audiencia = config.Audiencia;
29 string claveSecreta = config.ClaveSecreta;
30
31 var credencialesFirma = new SigningCredentials(
32 new SymmetricSecurityKey(Encoding.ASCII.GetBytes(claveSecreta)),
33 SecurityAlgorithms.HmacSha256
34 );
35
36 var claims = new Claim[] {
37 new Claim(JwtRegisteredClaimNames.Sid, usuario.IdUsuario),
38 new Claim(JwtRegisteredClaimNames.Iss, emisor),
39 new Claim(JwtRegisteredClaimNames.Sub, usuario.Nombre),
40 new Claim("IdentificadorUnico", Guid.NewGuid().ToString("D")),
41 new Claim("IdRol", usuario.IdRol.ToString()),
42 new Claim("Edad", usuario.Edad.ToString()),
43 new Claim("FechaNacimiento", usuario.FechaNacimiento.ToString())
44 };
45
46 var tokenSeguridad = new JwtSecurityToken(
47 emisor: emisor,
48 audiencia: audiencia,
49 credencialesFirma: credencialesFirma,
50 expires: DateTime.Now.AddMinutes(2),
51 claims: claims
52 );
53
54 return new JwtSecurityTokenHandler().WriteToken(tokenSeguridad);
55 }
56
57 /// <summary>
58 /// Obtiene el token del encabezado de autorización
59 /// </summary>
60 /// <param name="context">Contexto HTTP</param>
61 /// <returns>Token como string</returns>
62 public static string ObtenerToken(HttpContext context)
63 {
64 return context != null ? context.Request.Headers["Authorization"].ToString() : "";
65 }
66
67 /// <summary>
68 /// Decodifica y valida un token JWT
69 /// </summary>
70 /// <param name="tokenAcceso">Token a decodificar</param>
71 /// <returns>Información del token</returns>
72 public static InformacionToken DecodificarToken(string tokenAcceso)
73 {
74 try
75 {
76 if (tokenAcceso.Contains("Bearer"))
77 {
78 tokenAcceso = tokenAcceso.Replace("Bearer ", "");
79 }
80
81 var manejadorToken = new JwtSecurityToken(tokenAcceso);
82 InformacionToken infoToken = new InformacionToken
83 {
84 IdUsuario = manejadorToken.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Sid).Value,
85 Nombre = manejadorToken.Claims.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Sub).Value,
86 Edad = manejadorToken.Claims.FirstOrDefault(c => c.Type == "Edad").Value,
87 FechaNacimiento = manejadorToken.Claims.FirstOrDefault(c => c.Type == "FechaNacimiento").Value,
88 IdRol = manejadorToken.Claims.FirstOrDefault(c => c.Type == "IdRol").Value,
89 };
90 return infoToken;
91 }
92 catch (Exception ex)
93 {
94 throw new Exception("Error al decodificar el token: " + ex.Message);
95 }
96 }
97 }
98
99 public class InformacionToken
100 {
101 public string IdUsuario { get; set; }
102 public string Nombre { get; set; }
103 public string Edad { get; set; }
104 public string FechaNacimiento { get; set; }
105 public string IdRol { get; set; }
106 }
107 }
Ver código9: Entidad del modelo
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel.DataAnnotations;
4
5 namespace ProyectoWeb.Modelos
6 {
7 [Serializable]
8 public class usuario
9 {
10 [Required(ErrorMessage = "El nombre es obligatorio")]
11 [StringLength(maximumLength: 50, ErrorMessage = "El nombre no puede superar 50 caracteres")]
12 [MinLength(2, ErrorMessage = "El nombre debe tener al menos 2 caracteres")]
13 public string Nombre { get; set; }
14
15 [Range(1, 150, ErrorMessage = "La edad debe estar entre 1 y 150")]
16 public int Edad { get; set; }
17
18 [DataType(DataType.Date, ErrorMessage = "La fecha debe tener formato válido (ej: 1990-01-01)")]
19 public DateTime FechaNacimiento { get; set; }
20
21 [Required(ErrorMessage = "La contraseña es obligatoria")]
22 [StringLength(maximumLength: 20, MinimumLength = 6, ErrorMessage = "La contraseña debe tener entre 6 y 20 caracteres")]
23 public string Contraseña { get; set; }
24
25 public int IdRol { get; set; }
26 public string IdUsuario { get; set; }
27 }
28 }
Ver código10: Contenido de configuración:
11: Efectos de la prueba
Nota final: Por seguridad y optimización de recursos, generalmente solo incluimos identificadores de datos no sensibles en el token