Ao autenticar um usuário, nós podemos além de armazenar no token o seu nome, algumas outras propriedades que o descrevem, tais como: e-mail, papéis (roles), etc. Com isso, nós teremos diversas outras características dele além de apenas o nome e os papéis que ele possui dentro da aplicação.
Como sabemos, essas informações são expressadas através de claims. Ao autenticar, nós podemos criar uma coleção de claims contendo todas as informações sobre o respectivo usuário. Como as claims estão em todo lugar, o ASP.NET fornece um recurso específico que permite a transformação de claims, ou seja, além de utilizar informações que temos do lado do servidor para descrever o usuário, para complementar extraindo dados da requisição e incluir na coleção de claims.
Para customizar o tranformador, devemos implementar a interface IClaimsTransformer, e através do método TransformAsync podemos incrementar mais informações sobre o usuário e mais tarde utiliza-las para autorização de algum recurso específico. No exemplo abaixo, estamos extraindo a cultura (via header Accept-Language) da requisição e incluindo no ClaimsPrincipal gerado:
public class CultureToClaimTransformer : IClaimsTransformer
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
{
var principal = context.Principal;
if (principal.Identity.IsAuthenticated)
{
var culture = StringValues.Empty;
if (context.Context.Request.Headers.TryGetValue(“Accept-Language”, out culture))
((ClaimsIdentity)principal.Identity).AddClaim(new Claim(“Culture”, culture.ToString()));
}
return Task.FromResult(principal);
}
}
Só que a classe por si só não funciona. Precisamos incluir a mesma na execução, e para isso, recorremos ao método UseClaimsTransformation para indicar ao runtime do ASP.NET a classe que faz a transformação de claims. Depois do MVC devidamente configurado, estamos utilizando a autenticação baseada em cookies para o exemplo, indicamos a instância da classe CultureToClaimTransformer para a propriedade Transformer.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication();
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
LoginPath = “/Aplicacao/Login”,
ReturnUrlParameter = “ReturnUrl”,
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
app.UseClaimsTransformation(new ClaimsTransformationOptions()
{
Transformer = new CultureToClaimTransformer()
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: “default”,
template: “{controller=Aplicacao}/{action=Index}/{id?}”);
});
}
}
Depois de toda a configuração realizada, nós vamos codificar o nosso controller. Ele possui apenas dois métodos: um que exibe informações e o outro que onde de fato realizamos o login. O método que exibe as informações (Index) está decorado com o atributo AuthorizeAttribute, que não permitirá usuários não autenticados acessá-lo. Já o segundo método serve para autenticar o usuário; em uma aplicação real, este método deve receber as informações postadas em um formulário para validar primeiramente se o usuário existe (em uma base de dados, por exemplo), e caso verdadeiro, aí sim devemos proceder com a autenticação.
public class AplicacaoController : Controller
{
[Authorize]
public IActionResult Index()
{
return View();
}
public IActionResult Login()
{
HttpContext.Authentication.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(
new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, “Israel Aece”) },
CookieAuthenticationDefaults.AuthenticationScheme))).Wait();
return Redirect(Request.Query[“ReturnUrl”]);
}
}
Por fim, ao rodar a aplicação e exibir a coleção de claims do usuário logado, nós teremos duas: uma com o nome do usuário e a outra com a cultura que foi passada pelo navegador que o usuário está utilizando para acessar a aplicação:
- http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: Israel Aece
- Culture: pt-BR