Otra forma de manejar la seguridad es mediante Action Filters. Los action filters como ya lo vimos en el tema 5.5.1 Agregando una excepción a todos nuestros servicios .Net cuenta con Action Filters, los cuales se ejecutan antes de cada servicio, aquí es donde validamos que el usuario tenga permiso para realizar la acción.
El filtro de tipo Acción (IActionFilter) cuenta con los siguientes métodos
OnActionExecuting: El código dentro de esta función se ejecuta antes de cada servicio.
OnActionExecuted: El código dentro de esta función se ejecuta después de cada servicio. Más adelante utilizare este método para guardar el historial de que usuario ha agregado o modificado registros.
Vamos a agregar una clase BaseController, la cual contendrá las propiedades y métodos comunes a todos los controllers. En esta clase vamos a agregar un objeto de nuestra clase PermisoDTO para identificar el nombre de la tabla que deseamos validar.
Agregamos nuestra clase BaseController que hereda de la clase Controller, en la carpeta Controllers
2. Cambiamos nuestro controller ProductosController, para que herede de nuestra clase creada y agregamos los datos de nuestro objeto permisoDTO, en nuestro constructor agregamos nuestro constructor de la clase base.
3. En nuestra carpeta de Filters agregamos una nueva clase PermisoFilter que hereda de la clase IActionFilter.
4. En esta clase vamos a validar el permiso
PermisoFilter.cs
usingSystem;usingSystem.Security.Claims;usingCaducaRest.Controllers;usingCaducaRest.Core;usingCaducaRest.DAO;usingCaducaRest.Models;usingCaducaRest.Resources;usingMicrosoft.AspNetCore.Mvc;usingMicrosoft.AspNetCore.Mvc.Filters;namespaceCaducaRest.Filters;publicclassPermisoFilter:IActionFilter{privatereadonlyLocService _localizer;privatereadonlyCaducaContext _context;publicPermisoFilter(CaducaContext context,LocService localizer) {this._localizer= localizer;this._context= context; }publicvoidOnActionExecuted(ActionExecutedContext context) { } // Este método se ejecuta antes de cada acción (PUT, GET, // POST, PATCH, DELETE)publicvoidOnActionExecuting(ActionExecutingContext context) {JsonResult jsonResult;CustomError customError =newCustomError (403,"El usuario es inválido"); //Obtenemos los datos del usuarioClaimsPrincipal Usuario =context.HttpContext.User; //Se revisa si en el token se incluye el claim con el //id del usuarioif (!Usuario.HasClaim(c =>c.Type==ClaimTypes.Sid)) { //regresamos un mensaje de error jsonResult =newJsonResult(customError) { StatusCode =403, Value =customError.Message };context.Result= jsonResult;return; }var usuarioId =Convert.ToInt32(Usuario .FindFirst(c =>c.Type==ClaimTypes.Sid).Value); //Obtenemos los datos del controllervar controller =context.ControllerasBaseController;var metodo =controller.Request.Method.ToLower();RolDAO rolDAO =newRolDAO(_context, _localizer);bool esAdministrador =rolDAO.EsAdministrador(usuarioId); //Si el recurso requiere un usuario administrador // se valida que el usuario sea administrador, // si no es asi marcar errorif (controller.permiso.RequiereAdministrador&&!esAdministrador) { jsonResult =newJsonResult(customError) { StatusCode =403, Value =customError.Message };context.Result= jsonResult;return; }else {string operacion =string.Empty; //obtenemos el tipo de método que se esta ejecutandoswitch (metodo) {case"get": operacion =Operaciones.Consultar.Name;break;case"post": operacion =Operaciones.Crear.Name;break;case"put":case"patch": operacion =Operaciones.Modificar.Name;break;case"delete": operacion =Operaciones.Borrar.Name;break; } //Se revisa si el usuario tiene autorización para // realizar la acciónRolTablaPermisoDAO rolTablaPermisoDAO =newRolTablaPermisoDAO(_context, _localizer);if (!rolTablaPermisoDAO.TienePermiso(usuarioId,controller.permiso.Tabla, operacion)) { jsonResult =newJsonResult(customError) { StatusCode =403, Value =customError.Message };context.Result= jsonResult;return; } } }}
Si deseamos agregar esta validación a nuestros servicios agregamos nuestra clase PermisoFilter como atributo a nuestros Controller
Puedes agregar un breakpoint en el método OnActionExecuting para comprobar que antes de cada servicio se manda llamar el código de este método y comprobar que se valida correctamente los permisos.