Tendo usado várias técnicas de autenticação e autorização ao longo de décadas, meu aplicativo MVC atual usa a seguinte metodologia.
As reivindicações são usadas para todas as autorizações. Os usuários são atribuídos a uma função (várias funções são possíveis, mas eu não preciso disso) - mais abaixo.
Como é prática comum, uma classe de atributo ClaimsAuthorize é usada. Como a maioria das ações do controlador são CRUD, eu tenho uma rotina na geração do banco de dados do código que itera todas as ações do controlador e cria tipos de declaração para cada atributo de ação do controlador de Ler / Editar / Criar / Excluir. Por exemplo, de,
[ClaimsAuthorize("SomeController", "Edit")]
[HttpPost]
Para uso em uma visão MVC, uma classe de controlador de base apresenta itens de bolsa de visão
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 menus de sites e outras ações sem controle, tenho outras reivindicações. Por exemplo, se um usuário pode visualizar um campo monetário específico.
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");
}
}
Então, onde as funções se encaixam?
Eu tenho uma tabela que vincula uma função a um conjunto de declarações (padrão). Ao definir a autorização do usuário, o padrão é dar ao usuário as declarações de sua função. Cada usuário pode ter mais ou menos reivindicações do que o padrão. Para simplificar a edição, a lista de declarações é mostrada por controlador e ações (em uma linha), com outras declarações então listadas. Os botões são usados com um pouco de Javascript para selecionar um conjunto de ações para minimizar o "clique" necessário para selecionar reivindicações. Ao salvar, as reivindicações dos usuários são excluídas e todas as reivindicações selecionadas são adicionadas. O aplicativo da web carrega declarações apenas uma vez, portanto, quaisquer alterações devem solicitar uma recarga dentro desses dados estáticos.
Os gerentes podem, portanto, selecionar quais declarações estão em cada função e quais declarações um usuário possui após defini-lo para uma função e essas declarações padrão. O sistema tem apenas um pequeno número de usuários, portanto, o gerenciamento desses dados é simples