ASP .NET Core -  Implementando a segurança com autenticação via Cookies e ADO .NET - I

 Neste artigo eu vou mostrar como implementar a autenticação via cookie em uma aplicação ASP .NET Core usando a ADO .NET. 

Quando você cria uma aplicação ASP .NET Core MVC usando o template Web Application(Model-View-Controller) com autenticação através da opção Individual User Accounts,  o projeto criado possui toda a estrutura para realizar a autenticação e o registro do usuário.

A ASP.NET Core fornece várias maneiras de implementar a autenticação em uma aplicação. Neste artigo vou focar na autenticação via cookie.

Vou criar uma aplicação ASP .NET Core MVC onde iremos implementra o registro e o login de novos usuários. A persistência das informações será feita em um banco de dados SQL Server 2012 usando os  recursos da ADO .NET.

O objetivo é mostrar mais uma alternativa de implementação da segurança usando ASP .NET Core.

Vou usar a abordagem database-first onde iremos criar o banco de dados Estudo.mdf e a tabela Usuario com a seguinte estrutura:

 CREATE TABLE Usuarios
 (
   Id [int] IDENTITY(1,1) NOT NULL,
   Login [nvarchar](100) NOT NULL,
   Senha [nvarchar](100) NOT NULL, 
   Nome [nvarchar](100) NOT NULL,
   Email [nvarchar](150) NOT NULL
 )

A seguir vamos criar as seguintes stored procedures:

1- Para registrar um usuário

    CREATE PROCEDURE RegistrarUsuario
    (  
        @Login VARCHAR(100),  
        @Senha VARCHAR(100) ,  
        @Nome VARCHAR(100) ,  
        @Email VARCHAR(100)   
    )  
    AS  
    BEGIN        
        DECLARE @resultado VARCHAR(10) ='Falhou'      
        IF NOT EXISTS(SELECT 1 FROM Usuarios where Login=@Login)  
        BEGIN     
            INSERT INTO Usuarios  
            VALUES   
            (   
                @Login,@Senha,@Nome,@Email  
            )               
            SET @resultado= 'Sucesso'  
        END   
            SELECT @resultado AS Resultado  
    END  

2- Para validar o login do usuário

    CREATE PROCEDURE ValidarLogin  
    (  
        @Login VARCHAR(100) ,  
        @Senha VARCHAR(100)  
    )  
    AS  
    BEGIN        
        DECLARE @autenticacao VARCHAR(10)='Falhou'        
        IF EXISTS(SELECT 1 FROM Usuarios WHERE Login=@Login AND Senha =@Senha)  
        BEGIN  
            SET @autenticacao='Sucesso'  
        END  
        SELECT @autenticacao AS EstaAutenticado        
    END  

O resultado final obtido no SQL Server pode ser visto na figura abaixo:

Recursos usados:

Criando o projeto no VS 2017

Abra o VS 2017 Community e crie um novo projeto ASP .NET Core usando o template Empty.

  • Create New Project;
  • Visual C# -> Web -> ASP .NET Core Web Application;
  • Informe o nome AspCore_AutenticaCookie
  • Selecione o template Web Application(Model-View-Controller) , marque ASP .NET Core 2.0;

Confirme as opções clicando em OK para criar o projeto.

Vou iniciar definindo a string de conexão no appsettings.json :
 
{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=.\MACORATTI;Initial Catalog=Estudo;Integrated Security=True"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  }
}

Nota:  Você pode usar qualquer outro nome da sua escolha.

Definindo o modelo de domínio e a classe de acesso aos dados

Vamos criar na pasta Models do projeto as classes Usuario que representa um usuário e a classe Autenticacao que vamos usar para registrar e validar o login do usuário.    

1- Classe Usuario

Nesta classe definimos as propriedades do usuário:
 
using System.ComponentModel.DataAnnotations;

namespace AspCore_AutenticaCookie.Models
{
    public class Usuario
    {
        [Required]
        public string Login { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Senha { get; set; }

        [Required]
        [Display(Name = "Nome do usuário :")]
        public string Nome { get; set; }

        [Required]
        [Display(Name = "Email do usuário :")]
        [DataType(DataType.EmailAddress)]
        public string Email { get; set; }
    }
}

2- Classe de acesso aos dados

Para definir a lógica de acesso aos dados vamos definir a interface IAutenticacao e a classe Autenticacao que implementa esta interface. Dessa forma poderemos registrar o serviço para poder usar a injeção de dependência no construtor do controlador LoginController que iremos criar mais adiante.

a- Definindo a interface IAutenticacao
 
 public interface IAutenticacao
    {
        string GetConnectionString();
        string RegistrarUsuario(Usuario usuario);
        string ValidarLogin(Usuario usuario);
    }

b- Implementando a interface IAutenticacao na classe Autenticacao

A classe Autenticacao implementa a interface; nesta classe temos os métodos para registrar um usuário e validar o login do usuário.

O código permite ler a string de conexão definida no arquivo appsettings.json e acessar as tabelas do banco de dados usando ADO .NET :
 
using Microsoft.Extensions.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;

namespace AspCore_AutenticaCookie.Models
{
    public class Autenticacao : IAutenticacao
    {
        public IConfiguration Configuration { get; set; }

       //Le a string de conexão do arquivo de configuração
        public string GetConnectionString()
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json");

            Configuration = builder.Build();
            string connectionString = Configuration["ConnectionStrings:DefaultConnection"];
            return connectionString;
        }

        public string RegistrarUsuario(Usuario usuario)
        {
            using (SqlConnection con = new SqlConnection(GetConnectionString()))
            {
                SqlCommand cmd = new SqlCommand("RegistrarUsuario", con);
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.Parameters.AddWithValue("@Login", usuario.Login);
                cmd.Parameters.AddWithValue("@Senha", usuario.Senha);
                cmd.Parameters.AddWithValue("@Nome", usuario.Nome);
                cmd.Parameters.AddWithValue("@Email", usuario.Email);

                con.Open();
                string resultado = cmd.ExecuteScalar().ToString();
                con.Close();

                return resultado;
            }
        }

        public string ValidarLogin(Usuario usuario)
        {
            using (SqlConnection con = new SqlConnection(GetConnectionString()))
            {
                SqlCommand cmd = new SqlCommand("ValidarLogin", con);
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.Parameters.AddWithValue("@Login", usuario.Login);
                cmd.Parameters.AddWithValue("@Senha", usuario.Senha);

                con.Open();
                string resultado = cmd.ExecuteScalar().ToString();
                con.Close();

                return resultado;
            }
        }
    }
}

Configurando a autenticação via cookies e registrando o serviço

Vamos agora registrar o serviço e definir a autenticação via cookies no arquivo Startup.cs do projeto incluindo o código em azul destacado conforme abaixo:

using AspCore_AutenticaCookie.Models;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace AspCore_AutenticaCookie
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IAutenticacao, Autenticacao>();

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                    .AddCookie(options =>
                    {
                        options.LoginPath = "/Login/LoginUsuario/";

                    });

            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseAuthentication();

            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Login}/{action=LoginUsuario}/{id?}");
            });

        }
    }
}

No método ConfigureServices, estamos fazendo o seguinte :

  1. Configurando o nosso serviço de acesso aos dados registrando a interface e a classe concreta;
  2. Configurando o serviço de autenticação de cookies. Inicializamos as opções de autenticação de cookies, a propriedade options.LoginPath que indica a página para onde o usuário será redirecionado(a página de Login) se a autenticação falhar;

No método Configure estamos definindo o uso da autenticação e definindo um mapeamento para o controlador Login e a action LoginUsuario.

Criando os controllers LoginController e UsuarioController

Vamos incluir o controlador LoginController na pasta Controllers com seguinte código:
 
using AspCore_AutenticaCookie.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;

namespace AspCore_AutenticaCookie.Controllers
{
    public class LoginController : Controller
    {
        private readonly IAutenticacao _autentica;

        public LoginController(IAutenticacao autentica)
        {
            _autentica = autentica;
        }

        [HttpGet]
        public IActionResult RegistrarUsuario()
        {
            return View();
        }

        [HttpPost]
        public IActionResult RegistrarUsuario([Bind] Usuario usuario)
        {
            if (ModelState.IsValid)
            {
                string RegistroStatus = _autentica.RegistrarUsuario(usuario);
                if (RegistroStatus == "Sucesso")
                {
                    ModelState.Clear();
                    TempData["Sucesso"] = "Registro realizado com sucesso!";
                    return View();
                }
                else
                {
                    TempData["Falhou"] = "O Registro do usuário falhou.";
                    return View();
                }
            }
            return View();
        }

        [HttpGet]
        public IActionResult LoginUsuario()
        {
            return View();
        }

        [HttpPost]
        [ValidateAntiForgeryToken]

        public async Task<IActionResult> LoginUsuario([Bind] Usuario usuario)
        {
            ModelState.Remove("Nome");
            ModelState.Remove("Email");

            if (ModelState.IsValid)
            {
                string LoginStatus = _autentica.ValidarLogin(usuario);

                if (LoginStatus == "Sucesso")
                {
                    var claims = new List<Claim>
                    {
                        new Claim(ClaimTypes.Name, usuario.Login)
                    };

                    ClaimsIdentity userIdentity = new ClaimsIdentity(claims, "login");
                    ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);

                    await HttpContext.SignInAsync(principal);

                    if (User.Identity.IsAuthenticated)
                        return RedirectToAction("UsuarioHome", "Usuario");
                    else
                    {
                        TempData["LoginUsuarioFalhou"] = "O login Falhou. Informe as credenciais corretas " + User.Identity.Name;
                        return RedirectToAction("LoginUsuario", "Login");
                    }

                }
                else
                {
                    TempData["LoginUsuarioFalhou"] = "O login Falhou. Informe as credenciais corretas";
                    return View();
                }
            }
            else
            {
                return View();
            }
        }
    }
}

Neste código após injetar uma instância da classe  de acesso aos dados, Autenticacao, no construtor, temos os métodos:

  • LoginUsuario (GET/POST) - que valida o login do usuário;
  • RegistrarUsuario (GET/POST) - que registra um novo usuário no banco de dados;

Vamos agora incluir mais um controlador na pasta Controllers; o controlador UsuarioController que contém os métodos Actions:

  • UsuarioHome - Redireciona o usuário autenticado para a View UsuarioHome;
  • Logout - Faz o logout e redireciona o usuário para a página de Login;

Como não precisamos as propriedades Nome e Email para login estamos removendo os valores do nosso model usando o método ModelState.Remove.

O código é mostrado a seguir:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace AspCore_AutenticaCookie.Controllers
{
    [Authorize]
    public class UsuarioController : Controller
    {
       public IActionResult UsuarioHome()
       {
          return View();
       }

       [HttpGet]
       public async Task<IActionResult> Logout()
       {
           await HttpContext.SignOutAsync();
           return RedirectToAction("UsuarioLogin", "Login");
       }
    }
}

Na próxima parte do artigo vamos criar as respectivas Views e testar a autenticação usando cookies na nossa aplicação.

"Levantai os vossos olhos para os céus, e olhai para a terra em baixo, porque os céus desaparecerão como a fumaça, e a terra se envelhecerá como roupa, e os seus moradores morrerão semelhantemente; porém a minha salvação durará para sempre, e a minha justiça não será abolida."
Isaías 51:6
 
Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti