ASP .NET Core 3.1 - Autenticação com cookies
Neste artigo vamos abordar a autenticação via Cookies na ASP .NET Core 3.1. |
|
A ASP.NET Core fornece um middleware de cookies, que serializa um usuário principal em um cookie criptografado e, em requisições subsequentes, valida o cookie, recria o seu proprietário e o atribui à propriedade User em HttpContext.
Assim, se você deseja fornecer suas próprias telas de login e bancos de dados de usuários, pode usar o middleware de cookies como um recurso independente.
O middleware
de autenticação intercepta requisições recebidas e verifica a existência de um
cookie contendo dados do usuário criptografados.
Se um cookie for encontrado, ele será serializado em um tipo de
ClaimPincipal e poderá ser acessado através da
propriedade HttpContext.User.
Se um cookie não for encontrado, o middleware será redirecionado para a página
de login usando um método Action. Por meio da página de login, você recebe
detalhes do usuário e se autentica nos registros do banco de dados. Depois de
autenticado, você vai precisar :
Para isso vamos usar os conceitos relacionados aos seguintes recursos:
Opções de Cookies
As opções de cookie informam ao middleware de autenticação como o cookie se
comporta no navegador. Existem muitas opções, a seguir temos apenas naquelas que
afetam mais a segurança dos cookies.
Definir HttpOnly como false no cookie de autenticação substituirá as opções de política de cookies , e, ao definir o SameSite na política de cookies, as opções de cookies de autenticação são substituídas.
Neste exemplo vamos implementar a autentica via cookies sem usar o Identity.
Recursos :
Criando o projeto no VS 2019 Community
Abra o VS 2019 Community e crie uma solução em branco via menu File-> New Project;
Selecione o template ASP .NET Core Web Application, e, Informe o nome Aspnet_AuthCookies1;
A seguir selecione .NET Core e ASP .NET Core 3.1 e marque o template Web Application e as configurações conforme figura abaixo:
Podemos executar a aplicação pressionando F5 e veremos a página padrão do template exibida no navegador.
Integrando a autenticação com cookies
Como vamos implementar a autenticação via cookies sem usar o Identity precisamos configurar o middleware de cookies no método ConfigureServices da classe Startup:
... public void ConfigureServices(IServiceCollection services) { services.AddAuthentication("CookieAuthentication") .AddCookie("CookieAuthentication", config => { config.Cookie.Name = "UserLoginCookie"; config.LoginPath = "/Login/UserLogin"; config.AccessDeniedPath = "/Login/AccessDenied"; }); services.AddControllersWithViews(); } ... |
Neste código iniciamos o middleware de cookies e definimos o nome do cookie como UserLoginCookie que será criado, e, também definimos :
-
LoginPath - Caminho relativo para o qual as
requisições serão redirecionadas quando um usuário tentar acessar um recurso,
mas não tiver sido autenticado;
- AccessDeniedPath - (opcional) Caminho
relativo para o qual as requisições serão redirecionadas quando um usuário
tentar acessar um recurso, mas não passar nenhuma política de autorização para
esse recurso;
A seguir precisamos incluir os métodos de extensão UseAuthentication e UseAuthorization ao método Configure da classe Startup :
No método Configure inclua a chamada a esses middlewares na ordem indicada:
public
void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... ... // Quem é você? app.UseAuthentication(); // Verifica Permissões app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } |
A seguir vamos criar um modelo de domínio para identificar o usuário criando a classe Usuario e definindo um método GetUsuarios onde vamos atribuir valores aos dados de um usuário para efeito de teste.
Na pasta Models crie o arquivo Usuario.cs com o código abaixo:
public
class Usuario { public int Id { get; set; } public string Nome { get; set; } public string Login { get; set; } public string Email { get; set; } public string Password { get; set; } public IEnumerable<Usuario> GetUsuarios() { return new List<Usuario>() { new Usuario { Id = 101, Nome = "Jose Carlos", Login = "macoratti", Email = "macoratti@teste.com", Password = "#numsey@" } }; } } |
Ajustando o controlador HomeController e as suas views
Vamos alterar o código do controlador HomeController criado na pasta Controllers e vamos definir dois métodos Action:
using
Aspnet_AuthCookies1.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Aspnet_AuthCookies1.Controllers { public class HomeController : Controller { public IActionResult Index() { var usuario = "Anônimo"; var autenticado = false; if (HttpContext.User.Identity.IsAuthenticated) { usuario= HttpContext.User.Identity.Name; autenticado = true; } else { usuario = "Não Logado"; autenticado = false; } ViewBag.usuario = usuario; ViewBag.autenticado = autenticado; return View(); } [Authorize] public ActionResult Usuarios() { var usuario = new Usuario(); return View(usuario.GetUsuarios()); } } } |
Observe que o método Action Usuarios() esta decorado com o atributo [Authorize] que vai permitir acesso somente aos usuários autenticados.
Agora vamos ajustar o código da view Index.cshtml da pasta /Views/Home conforme abaixo:
@ViewBag.usuario
<div>
@if (@ViewBag.autenticado == true)
{
<form method="post" asp-controller="Login" asp-action="Logout">
<input class="btn btn-link" type="submit" value="Logout" />
</form>
}
</div>
<hr />
<div class="jumbotron">
<h1 class="display-4">Macoratti .net</h1>
</div>
|
Este código exibie o status do usuário e verifica se o mesmo esta autenticado. Se estive então exibie o link para fazer o logout acionando o controlador Login e o método Action Logout.
Agora vamos criar a view Usuarios e para isso clique com o botão do mouse sobre o método Action Usuarios e a seguir selecione Add View;
Depois informa o nome da view como Usuarios e escolha o template Empty e marque para usar a página de leiaute conforme mostra a figura abaixo:
Agora inclua o código abaixo na view Usuarios.cshtml da pasta /Views/Home :
@model IEnumerable<Aspnet_AuthCookies1.Models.Usuario>
@{
ViewData["Title"] = "Index";
}
<h1>Usuários</h1>
<table class="table">
<thead>
<tr>
<th>@Html.DisplayNameFor(model => model.Id)</th>
<th>@Html.DisplayNameFor(model => model.Nome)</th>
<th>@Html.DisplayNameFor(model => model.Login)</th>
<th>@Html.DisplayNameFor(model => model.Email)</th>
<th>@Html.DisplayNameFor(model => model.Password)</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@Html.DisplayFor(modelItem => item.Id)</td>
<td>@Html.DisplayFor(modelItem => item.Nome)</td>
<td>@Html.DisplayFor(modelItem => item.Login)</td>
<td>@Html.DisplayFor(modelItem => item.Email)</td>
<td>@Html.DisplayFor(modelItem => item.Password)</td>
<td>
@Html.ActionLink("Edita", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Detalhe", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Deleta", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</tbody>
</table>
|
Este código apenas vai exibir a lista de usuários definidos e somente poderá acessada se o usuário estiver autenticado.
Criando o controlador LoginController
No arquivo appsettings.json vamos incluir o código que define a string de conexão com uma instância do SQL Server local:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"ConnectionStrings": {
"sqlConnection": "Data Source=Macoratti;Initial Catalog=CadastroDB;Integrated Security=True"
},
"AllowedHosts": "*"
}
|
Nota : A migração deve ser aplicada apenas se você não possuir o banco de dados e a tabela definidas.
Com isso, já temos tudo pronto e agora podemos aplicar o Migrations para gerar o banco de dados e a tabela.
Abrindo uma janela do Package Manager Console e digitar o comando para criar a migração: Add-Migration Inicial
Será criado o arquivo de script de migração na pasta Migrations :
Para aplicar o script basta digitar : Update-database
Criando o controlador LoginController
Vamos criar o controlador LoginController e definir os seguintes métodos Actions:
Clique com o botão direito sobre a pasta Controllers e a seguir clique em Add -> Controller;
Escolha o template MVC Controller Empty e informe o nome LoginController;
A seguir inclua o código abaixo no controller:
using Aspnet_AuthCookies1.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Aspnet_AuthCookies1.Controllers
{
public class LoginController : Controller
{
[HttpGet]
public ActionResult UsuarioLogin()
{
return View();
}
[HttpPost]
public ActionResult UsuarioLogin([Bind] Usuario _usuario)
{
var usuario = new Usuario();
if (usuario.GetUsuarios().Any(u => u.Login == _usuario.Login && u.Password == _usuario.Password))
{
var userClaims = new List<Claim>()
{
//define o cookie
new Claim(ClaimTypes.Name, _usuario.Login),
new Claim(ClaimTypes.Email, "macoratti@teste.com"),
};
var minhaIdentity = new ClaimsIdentity(userClaims, "Usuario");
var userPrincipal = new ClaimsPrincipal(new[] { minhaIdentity });
//cria o cookie
HttpContext.SignInAsync(userPrincipal);
return RedirectToAction("Index", "Home");
}
ViewBag.Message = "Credenciais inválidas...";
return View(_usuario);
}
[HttpPost]
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync();
return RedirectToAction("Index", "Home");
}
}
}
|
Para criar o formulário de login vamos criar a view UsuarioLogin a partir do método Action UsuarioLogin e incluindo o código abaixo no arquivo UsuarioLogin.cshtml :
@model Aspnet_AuthCookies1.Models.Usuario
@{
ViewData["Title"] = "Login";
}
<div class="row">
<div class="col-md-4">
<form asp-action="UsuarioLogin">
<h2>User Login</h2>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Login" class="control-label"></label>
<input asp-for="Login" class="form-control" />
<span asp-validation-for="Login" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password" class="control-label"></label>
<input type="password" asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Login" class="btn btn-default btn-primary" />
</div>
</form>
</div>
</div>
<br />
<h2>@ViewData["Message"]</h2>
|
Para concluir vamos ajustar o arquivo _Layout.cshtml da pasta /Views/Shared para exibir o link e acessar os usuários:
...
<div class="navbar-collapse collapse d-sm-inline-flex
flex-sm-row-reverse"> |
Agora é só alegria...
Executando o projeto iremos inicialmente acessar a página Index.cshtml onde poderemos clicar no link para acessar os usuários.
Como não estamos autenticados seremos direcionados para página de Login (UsuarioLogin.cshtml).
Informando as credenciais corretas estaremos autenticados e poderemos acessar a página para exibir os usuários:
Observe que podemos acessar o cookie armazenado no navegador pressionado F12(No Firefox), e assim, excluindo o cookie, voltamos ao estado inicial de não autenticado.
Pegue o projeto aqui: Aspnet_AuthCookies1.zip (sem as referências)
"Ai dos que
ajuntam casa a casa, reúnem campo a campo, até que não haja mais lugar, e fiquem
como únicos moradores no meio da terra!"
Isaías 5:8
Referências:
Curso Fundamentos da Programação Orientada a Objetos com VB .NET
Jose C Macoratti (@macorati) | TwitterSeção Entity Framework - Macoratti .NET
ASP .NET Core - Implementando a segurança com ... - Macoratti
ASP.NET Core MVC - Criando um Dashboard ... - Macoratti.net
Entity Framework - Separando as classes das entidades do EDM(.edmx) em projetos distintos
ASP .NET Core - Apresentando Razor Pages - Macoratti
ASP .NET Core MVC - CRUD básico com ADO .NET - Macoratti
ASP .NET Core - Implementando e consumindo JWT - Macoratti
ASP .NET Core - Criando uma API CRUD - I - Macoratti.net
ASP .NET Core - Criando sua primeira Web API ... - Macoratti