ASP .NET Core Identity - Como trabalhar com Claims - I
Neste artigo veremos como trabalhar com claims usando a ASP .NET Core Identity. |
Eu já publiquei diversos artigos abordando o ASP .NET Core Identity e hoje vou focar na utilização do recurso claims.
O que são e como atuam as Claims
As claims ou declarações são um par nome-valor emitido por uma parte confiável. Por exemplo, a carteira de habilitação de uma pessoa é emitida por uma autoridade de habilitação. Se a 'Data de Nascimento' na carteira de habilitação for 21 de março de 1995. Nesse caso, o nome da claim seria 'Data de Nascimento', o valor da claim seria 21 de março de 1995 e o emissor seria a autoridade da carteira de habilitação.
A autorização baseada em claims ou declarações, verifica o valor de uma claim/declaração e permite o acesso a um recurso com base no valor e na política de autorização definida, sendo que uma identidade pode conter várias claims/declarações com vários valores e pode conter várias claims/declarações do mesmo tipo.
As verificações de autorização baseadas em claims são declarativas - o desenvolvedor as incorpora em seu código, contra um controlador ou uma Action em um controlador, especificando as claims que o usuário atual deve possuir e, opcionalmente, o valor que a claim deve conter para acessar o recurso solicitado.
O tipo mais simples de política baseada em claim é aquela que apenas procura a presença de uma claim e não verifica o valor.
Assim, a primeira coisa a fazer, é criar e registrar a política baseada em claims e isso pode ocorrer como parte da configuração do serviço de autorização, que normalmente faz parte do método ConfigureServices() no arquivo Startup.cs.
Exemplo:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
services.AddAuthorization(options =>
{
options.AddPolicy("SomenteFuncionario", policy => policy.RequireClaim("FuncionarioNumero"));
});
} |
Nesse caso, a
política SomenteFuncionario verifica a presença de
uma claim ou declaração FuncionarioNumero
na identidade atual. Note que aqui não estamos verificando o valor.
Em seguida, você aplica a política usando a propriedade
Policy no atributo Authorize
para especificar o nome da política;
[Authorize (Policy = "SomenteFuncionario")] public IActionResult SaldoFolgasMensais() { return View (); } |
O atributo Authorize pode ser aplicado a um controlador e neste caso, apenas as identidades que correspondem à política terão acesso permitido a qualquer método Action no controlador.
Entendendo Claims
Para mostrar como as claims atuam e como funcionam eu vou criar um projeto ASP .NET Core MVC com autenticação individual onde vou implementar o autorização inicial baseada no email e senha do usuário. Esse é o padrão quando você criar um projeto usando o template padrão do Visual Studio 2019.
Vamos criar o projeto chamado AspnIdentityClaims usando o template ASP.NET Core Web Application usando o .NET Core 5.0 e configurar o projeto MVC.
Desta forma, para focar apenas nas claims vou partir do projeto já criado e com a autorização para o usuário com senha e email já implementada.
Vamos apresentar o projeto antes de prosseguir iniciando com o arquivo de projeto .csproj :
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
|
No arquivo de projeto vemos que estamos no ambiente do .NET 5.0 e os pacotes usados para configurar o Identity.
A seguir temos a estrutura do projeto :
Vamos implementar a autenticação baseada em claims ou declarações que na sua forma mais simples, verifica o valor de uma declaração e permite o acesso a um recurso com base nesse valor.
Gerenciando Claims
Vamos criar um novo controlador na pasta Controllers com o nome ClaimsController e alterar o seu método Action Index para retornar User.Claims conforme mostra o código a seguir:
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc;
namespace AspnIdentityClaims.Controllers |
Aqui, a propriedade User (também disponível como a propriedade HttpContext.User) retorna um objeto ClaimsPrincipal do usuário conectado.
Estamos assim obtendo todas as claims do usuário (como um objeto IEnumerable) usando a propriedade Claims do objeto ClaimsPrincipal, que estamos retornando para a View como um modelo.
Vamos criar a view Index.cshtml na pasta Views/Claims para exibir os dados das claims :
@model IEnumerable<System.Security.Claims.Claim> <h2 class="bg-primary m-1 p-1 text-white">Claims</h2> <table class="table table-sm table-bordered"> @foreach (var claim in Model.OrderBy(x => x.Type)) </table> |
Neste código a view vai exibir todas as claims ou declarações do usuário conectado em uma tabela HTML.
Para poder exibir o link que acessa esta view vamos alterar o arquivo _Layout.cshtml incluindo esta opção :
... <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between"> <ul class="navbar-nav flex-grow-1"> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a> </li> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-controller="Admin" asp-action="Index">Admin</a> </li> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-controller="Claims" asp-action="Index">Claims</a> </li> </ul> <partial name="_LoginPartial" /> </div> ... |
Executando o projeto e fazendo o login poderemos acessar e exibir as claims do usuário logado conforme abaixo:
Vamos agora implementar a criação e a exclusão de claims iniciando com a criação de claims.
Vamos abrir o controlador ClaimsController e definir os métodos Action Create para GET e POST, para isso vamos ter que injetar uma instância da classe UserManager<AppUser> no construtor do controlador:
using AspnIdentityClaims.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using System.Security.Claims; using System.Threading.Tasks;
namespace AspnIdentityClaims.Controllers public ViewResult Index() => View(User?.Claims); public ViewResult Create() => View(); [HttpPost] if (result.Succeeded) |
No método Action Create, primeiro obtemos o usuário atual conectado no método userManager.GetUserAsync().
Em seguida, adicionamos um novo objeto claim : new Claim(claimType, claimValue, ClaimValueTypes.String);
Por fim, incluímos esse objeto claim para criar uma nova claim para meu usuário. A declaração é criada para um usuário usando o método - userManager.AddClaimAsync()
A seguir vamos criar a view Create.cshtml na pasta Views/Claims :
<h1 class="bg-info text-white">Create Claim</h1> <a asp-action="Index" class="btn btn-secondary">Back</a> <div asp-validation-summary="All" class="text-danger"></div> <form method="post"> <button type="submit" class="btn btn-primary">Create</button> |
Neste código temos 2 controles input que permitirão adicionar o tipo de claim e o seu valor para um usuário.
A seguir vamos atualizar a View Index.cshtml do do método Index do controlador ClaimsController incluindo um link para invocar a view Create e um formulário que contém um botão para excluir uma claim existente.
@model IEnumerable<System.Security.Claims.Claim> <h2 class="bg-primary m-1 p-1 text-white">Claims</h2> <a asp-action="Create" class="btn btn-secondary">Create a Claim</a> <table class="table table-sm table-bordered"> @foreach (var claim in Model.OrderBy(x => x.Type)) </table> |
A seguir vamos completar o código do controlador ClaimsController incluindo o método Action Delete:
... [HttpPost] public async Task<IActionResult> Delete(string claimValues) { AppUser user = await userManager.GetUserAsync(HttpContext.User);
string[] claimValuesArray = claimValues.Split(";"); Claim claim = User.Claims.Where(x => x.Type == claimType IdentityResult result = await userManager.RemoveClaimAsync(user, claim); if (result.Succeeded) return View("Index"); ... |
O método Delete obtemos os valores da claim, que são separados por ponto e vírgula (;), em seu parâmetro.
Em seguida, com o
método de split, extraiamos o tipo da claim,
o seu valor e os valores do emissor da claim;
As claims selecionadas são localizadas usando a consulta LINQ:
Claim claim = User.Claims.Where(x => x.Type == claimType && x.Value == claimValue
&& x.Issuer == claimIssuer).FirstOrDefault();
|
A exclusão da claim do usuário é feita usando o método userManager.RemoveClaimAsync().
Vamos testar esses recursos, executando o projeto e fazendo o login com o usuário macoratti.
A seguir vamos criar uma claim definindo o tipo da claim como Desenvolvedor e o valor como ASP.NET Core.
Lembre-se de que, uma vez que uma claim é criada, você precisa fazer o login mais uma vez, a fim de ver a sua claim criada. Então, faça login na conta mais uma vez.
Em seguida acione o link para exibir as claims e você verá a claim criada:
Agora exclua sua claim recém-adicionada clicando no botão
Delete ao lado dela.
Depois que a reivindicação for excluída, você precisará fazer login novamente e,
em seguida, acessar o link das claims novamente:
Para poder realizar a autenticação dos usuários usando as claims precisamos definir as políticas.
Em outro artigo veremos como definir políticas para as claims.
Pegue o projeto aqui: AspnIdentityClaims.zip
"Porque Deus
não nos destinou para a ira, mas para a aquisição da salvação, por nosso Senhor
Jesus Cristo,
Que morreu por nós, para que, quer vigiemos, quer durmamos, vivamos juntamente
com ele."
1 Tessalonicenses
5:9,10
Referências:
ASP .NET Core - Implementando a segurança com
ASP.NET Core MVC - Criando um Dashboard .
C# - Gerando QRCode - Macoratti
ASP .NET - Gerando QRCode com a API do Google