Aplicando roles. Continuación de autenticación JWT
Antes de leer el artículo, por favor, lea aquí
Código disponible GitHub.
Continuamos donde lo dejamos en AQUÍ
Preparando tablas
Para agregarle roles a nuestra API necesitamos crear una tabla en la base de datos que contendrá los roles
En la carpeta Datos creamos una nueva clase Rol.cs
1 2 3 4 5 6 7 |
[Table("Roles")] public class Rol { [Key] [Required] public Guid Id { get; set; } = Guid.NewGuid(); [Required] public string Nombre { get; set; } = string.Empty; } |
En el fichero Usuario.cs donde esta el modelo del usuario agregamos las siguientes dos propiedades, creando una relación de uno a muchos entre rol y usuario
1 2 3 |
[Required] public Guid RolId { get; set; } = Guid.Empty; [ForeignKey("RolId")] public Rol? Rol { get; set; } |
Nos corresponde actualizar la base de datos, para eso creamos la migración en la Consola de administración de paquetes:
1 2 |
add-migration SoporteRoles update-database |
Usamos el editor de nuestra preferencia y creamos dos roles dentro de la tabla, Administrador y Basico
Modificando la creación del token
En el controlador de Autenticación(AuthController) en el método Autenticar
1 2 3 4 5 6 7 8 9 10 |
//la linea donde buscamos el usuario y la contraseña... var data = await _context.Usuarios .Where(w =>w.NombreUsuario == loginRequest.NombreUsuario && w.Password == GetSha1(loginRequest.Password)) .FirstOrDefaultAsync(); //le indicamos que incluya el objeto Rol que le corresponde a ese usuario con la sentencia INCLUDE var data = await _context.Usuarios.Where(w => w.NombreUsuario == loginRequest.NombreUsuario && w.Password == GetSha1(loginRequest.Password)) .Include(i=> i.Rol) .FirstOrDefaultAsync(); |
debemos modificar igualmente el método CrearToken:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
//Donde creamos el claim, en el ejemplo inicial pusimos el rol Admin por defecto new(ClaimTypes.Role, "Admin") // lo cambiamos por new(ClaimTypes.Role, usuario.Rol.Nombre) //Quedando el método completo así private string CrearToken(Usuario usuario) { var claims = new List<Claim> { new(ClaimTypes.Name, usuario.NombreUsuario), new(ClaimTypes.Role, usuario.Rol.Nombre), }; var key = new SymmetricSecurityKey( Encoding.UTF8.GetBytes(_configuration.GetSection("AppSettings:Token").Value!)); var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature); var token = new JwtSecurityToken( claims: claims, expires: DateTime.Now.AddDays(1), signingCredentials: cred ); var jwt = new JwtSecurityTokenHandler().WriteToken(token); return jwt; } |
Aplicando roles
Ya tenemos todo listo, en el controlador PersonaController si queremos que sea acceso exclusivo de administrador:
1 2 3 4 5 |
//la etiqueta: [Authorize] //la cambiamos por [Authorize(Roles = "Administrador")] |
Conclusiones
Solo nos queda comentar que si queremos hacer una aplicación donde los usuarios tendrán varios roles, solo tenemos que crear una tabla con el ID del usuario y el ID del rol(relación muchos a muchos) y la creación del claim sería algo así
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//sustituir var claims = new List<Claim> { new(ClaimTypes.Name, usuario.NombreUsuario), new(ClaimTypes.Role, usuario.Rol.Nombre), }; // por var claims = new List<Claim> { new(ClaimTypes.Name, usuario.NombreUsuario) }; var userRoles = _context.UsuariosRoles .Where(w => w.UsuarioId == usuario.Id) .Include(i => i.Rol) .ToList(); if (userRoles.Count != 0) foreach (var item in userRoles) claims.Add(new Claim(ClaimTypes.Role, item.Rol!.Nombre!)); |
Y para dar acceso a los controladores:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* * Ejemplo de roles: * - Administrador * - Operador * - Usuario */ //Acceso a usuarios con el rol operador o usuarios con el rol usuario [Authorize(Roles = "Operador, Usuario")] //Acceso a usuarios que tengan los dos roles(no uno solo) [Authorize(Roles = "Operador")] [Authorize(Roles = "Usuario")] |
Aquí termina esta serie, el código esta disponible en GitHub.
Déjenos un comentario o puede ponerse en contacto con nosotros a través de la web www.yhd.cu