Después de haber utilizado varias técnicas de autenticación y autorización durante décadas, mi aplicación MVC actual utiliza la siguiente metodología.
Las reclamaciones se utilizan para todas las autorizaciones. A los usuarios se les asigna un rol (son posibles varios roles, pero no los necesito) - más abajo.
Como es práctica común, se utiliza una clase de atributo ClaimsAuthorize. Dado que la mayoría de las acciones del controlador son CRUD, tengo una rutina en la generación de la base de datos de código primero que itera todas las acciones del controlador y crea tipos de reclamaciones para cada atributo de acción del controlador de lectura / edición / creación / eliminación. Por ejemplo, de
[ClaimsAuthorize("SomeController", "Edit")]
[HttpPost]
Para usar en una vista MVC, una clase de controlador base presenta elementos de bolsa de vista
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
// get user claims
var user = filterContext.HttpContext.User as System.Security.Claims.ClaimsPrincipal;
if (user != null)
{
// Get all user claims on this controller. In this controler base class, [this] still gets the descendant instance type, hence name
List<Claim> claims = user.Claims.Where(c => c.Type == this.GetType().Name).ToList();
// set Viewbag with default authorisations on this controller
ViewBag.ClaimRead = claims.Any(c => c.Value == "Read");
ViewBag.ClaimEdit = claims.Any(c => c.Value == "Edit");
ViewBag.ClaimCreate = claims.Any(c => c.Value == "Create");
ViewBag.ClaimDelete = claims.Any(c => c.Value == "Delete");
}
base.OnActionExecuting(filterContext);
}
Para los menús del sitio web y otras acciones ajenas al controlador, tengo otros reclamos. Por ejemplo, si un usuario puede ver un campo monetario en particular.
bool UserHasSpecificClaim(string claimType, string claimValue)
{
// get user claims
var user = this.HttpContext.User as System.Security.Claims.ClaimsPrincipal;
if (user != null)
{
// Get the specific claim if any
return user.Claims.Any(c => c.Type == claimType && c.Value == claimValue);
}
return false;
}
public bool UserHasTradePricesReadClaim
{
get
{
return UserHasSpecificClaim("TradePrices", "Read");
}
}
Entonces, ¿dónde encajan los roles?
Tengo una tabla que vincula un rol a un conjunto (predeterminado) de reclamaciones. Al configurar la autorización del usuario, el valor predeterminado es otorgar al usuario los reclamos de su función. Cada usuario puede tener más o menos reclamos que el predeterminado. Para simplificar la edición, la lista de reclamos se muestra por controlador y acciones (en una fila), y luego se enumeran otros reclamos. Los botones se utilizan con un poco de Javascript para seleccionar un conjunto de acciones para minimizar el "clic" requerido para seleccionar reclamos. En Guardar, se eliminan las reclamaciones de los usuarios y se agregan todas las reclamaciones seleccionadas. La aplicación web carga reclamos solo una vez, por lo que cualquier cambio debe provocar una recarga dentro de estos datos estáticos.
Por lo tanto, los administradores pueden seleccionar qué reclamos están en cada rol y qué reclamos tiene un usuario después de establecerlos en un rol y esos reclamos predeterminados. El sistema tiene solo una pequeña cantidad de usuarios, por lo que administrar estos datos es sencillo