Se você não é um extraterreste, com certeza já ouviu falar de ASP.NET MVC (caso seja, recomendo fortemente a leitura da série introdutória à tecnologia que escrevi neste site).
Quando web developers acostumados a trabalhar com ASP.NET iniciam o processo natural de migração para ASP.NET MVC, muitas dúvidas surgem. Apenas para relatar algumas: “Como faço para utilizar meu gridview?”, “No ASP.NET tinha os componentes validator’s. Como faço no ASP.NET MVC?”, “Como faço para autenticar usuários?”, etc.
Assim, este post pretende apresentar uma das formas disponíveis para realizar a autenticação de usuários em seu site/blog/sistema utilizando ASP.NET MVC 3 com Razor. Para nos auxiliar neste processo, utilizaremos cookies criptografadas (isso porque evitamos sempre que possível a utilização de sessions, pelos motivos já conhecidos: performance, sobrecarga do servidor, etc.).
A estrutura do banco de dados
Para construção do exemplo, utilizaremos uma estrutura de tabela relativamente simples de banco de dados. Esta tabela está presente no famoso banco “AdventureWorks“, disponibilizado gratuitamente pela Microsoft para estudos/testes e está definida como “Person.Contact”. Sua estrutura pode ser visualizada na Figura 1. Você pode baixar o Adventure Works e outros exemplos gratuitamente no CodePlex, clicando AQUI. O processo de instalação do Adventure Works em seu sistema pode ser encontrado AQUI.
Figura 1: Estrutura da tabela “Person.Contact”
O que fiz a seguir foi adicionar um registro à tabela com minhas informações pessoais para realizar o teste de autenticação. Pré requisitos atendidos, vamos a construção de nossa aplicação de exemplo.
Criando o projeto ASP.NET MVC 3
Para construção deste exemplo, estou utilizando o Visual Studio 2010 Ultimate, entretanto, você pode obter os mesmos resultados utilizando Visual Web Developer Express. Assim, com sua IDE em execução, crie um novo projeto do tipo ASP.NET MVC 3. A Figura 2 ilustra este procedimento.
Figura 2: Criando o projeto ASP.NET MVC 3
Clicando em “Ok”, o Visual Studio inicia o processo de criação do projeto e, antes que esse seja concluído, você deverá ser perguntado quanto a view engine que será utilizada. Como você já deve ter visto/ouvido, o padrão para o ASP.NET MVC 3 é Razor, entretanto, você não é obrigado a utilizá-la (opcionalmente, você pode utilizar ASP.NET tradicional). Além disso, nesta mesma tela, você pode optar por criar um projeto baseado em um modelo do VS 2010 ou um projeto vazio. Criaremos um projeto vazio e utilizaremos o Razor como engine padrão. A Figura 3 ilustra estas escolhas.
Figura 3: Escolhendo a view engine padrão e o tipo de projeto
Construindo a página master
Iniciaremos pela construção da view master. Portanto, na solution explorer, vá até a pasta “Views/Shared” e dê um duplo clique no arquivo “_Layout.cshtml“. Esta será nossa página master. Onde isso está definido? No arquivo “_ViewStart.cshtml” um nível de diretórios abaixo, como pode ser visualizado na Listagem 1.
[csharp]
Layout = “~/Views/Shared/_Layout.cshtml”;
[/csharp]
Listagem 1: Definição de “_Layout.cshtml” como master do projeto
Naturalmente, é possível definir outro arquivo como página master, entretanto, para este exemplo, manteremos a estrutura atual. Assim, no interior da página master (_Layout.cshtml), adicione o código fonte apresentado pela Listagem 2.
[html]
<html>
<head>
<title>@ViewBag.Title</title>
<link href=”@Url.Content(“~/Content/Site.css”)” rel=”stylesheet” type=”text/css” />
<script src=”@Url.Content(“~/Scripts/jquery-1.4.4.min.js”)” type=”text/javascript”></script>
</head>
<body>
<div id=”BoxGeral”>
@RenderBody()
</div>
</body>
</html>
[/html]
Listagem 2: Definindo os padrões visuais da página master
Para gerar o padrão visual, precisamos definir o estilo (CSS) que formata os elementos. Assim, utilizamos o arquivo CSS disponível na pasta Content (Site.css) para definir os estilos da master. Assim, adicione o trecho de código apresentado pela Listagem 3 no interior do arquivo mencionado.
[css]
body
{
font-family: Verdana, Tahoma, Arial, “Helvetica Neue”, Helvetica, Sans-Serif;
background-color:#EFEFEF;
}
#BoxGeral
{
width:800px;
padding:15px;
border-radius:7px 7px 7px 7px;
margin-left:auto;
margin-right:auto;
margin-top:20px;
text-align:left;
background-color:#FFF;
}
[/css]
Listagem 3: Configuração da página master
O resultado das operações executadas acima, pode ser visualizado na Figura 4.
Figura 4: Resultado da configuração da página master
Construindo o formulário de autenticação
Agora que já possuímos nossa “master page“, podemos passar a fase seguinte e construir nossa view onde o formulário de autenticação estará hospedado. Assim, na solution explorer, vá até a pasta “Controllers” e clique com o botão direito sobre a mesma. Selecione a opção “Add” e, em seguida, “Controller”. Nomeie seu controller conforme a conveniência (neste exemplo, seu nome será Home). A Figura 5 ilustra este procedimento.
Figura 5: Criando o controller responsável pela gerência da autenticação
Se tudo correu bem, sua solution explorer deve ter sofrido alguma alteração, isto é, um novo arquivo (HomeController.cs) deve ter sido adicionado a pasta Controllers. Dê um duplo clique sobre este arquivo. No editor de código, clique com o botão direito sobre o nome da action “Index.cshtml” e selecione a opção “Add view…“. Na janela que se abre, mantenha o nome padrão da view e selecione a opção “Use a layout or master page” e navegue pela árvore de diretórios do projeto até chegar no arquivo trabalhado por nós anteriormente como master page, isto é, Layout.cshtml, conforme ilustrado pela Figura 6.
Figura 6: Adicionando nova view ao projeto
Como estamos trabalhando com o conceito de page layout’s, na view nos preocuparemos apenas com com as informações inerentes a ela, isto é, sem preocupação com aspectos gerais visuais da aplicação. Assim, na solution explorer, dê um duplo clique sobre o arquivo Index.cshtml, localizado na pasta Views/Home. Em seu interior, adicione o código apresentado pela Listagem 4.
[html]
@{
ViewBag.Title = “Sistema Administrativo”;
Layout = “~/Views/Shared/_Layout.cshtml”;
}
<div id=”BoxTitulo”>
<h1>
Você é você?
</h1>
</div>
<div id=”BoxFormsGeral”>
<div id=”BoxFormLogin”>
<fieldset>
<legend>Informe seus dados</legend>
<form method=”post” action=”/Home/Index” id=”frmLogin”>
<table style=”margin-top:10px;”>
<tr>
<td>
Usuário:
</td>
<td>
<input type=”text” name=”txtUsuario” id=”txtUsuario” maxlength=”20″ class=”” />
</td>
</tr>
<tr>
<td>
Senha:
</td>
<td>
<input type=”password” name=”txtSenha” id=”txtSenha” maxlength=”10″ class=”” />
</td>
</tr>
<tr>
<td>
<input type=”submit” name=”btnEntrar” id=”btnEntrar” value=”Entrar” />
</td>
</tr>
</table>
</form>
</fieldset>
</div>
<div id=”BoxCadastro”>
<fieldset>
<legend>Cadastre-se</legend>
<span style=”margin-top:15px;”>
Ainda não se cadastrou em nosso portal? Cadastre-se agora mesmo!<br /><br />
<input type=”button” value=”Cadastrar agora!” id=”btnCadastrar” />
</span>
</fieldset>
</div>
</div>
<div id=”BoxOutrasInformacoes”>
<a href=”@Href(“~/Usuarios/Relembrar”)” target=”_self” class=”LinkGeral”>
Esqueceu seu usuário e/ou senha?
</a>
</div>
[/html]
Listagem 4: Criando o formulário de autenticação
O código é simples e dispensa comentários. Para que a formatação dos elementos adicionados a view possam ocorrer satisfatóriamente, adicione ao arquivo Site.css o techo de código CSS apresentado pela Listagem 5.
[css]
#BoxTitulo
{
width:100%;
float:left;
margin-bottom:20px;
}
#BoxFormsGeral
{
width:100%;
float:left;
margin-bottom:10px;
display:inline-block;
}
#BoxOutrasInformacoes
{
width:100%;
float:left;
display:inline-block;
}
#BoxFormLogin
{
width:370px;
display:inline-block;
float:left;
text-align:left;
padding:15px;
}
#BoxCadastro
{
width:370px;
display:inline-block;
float:right;
text-align:left;
padding:15px;
}
/* Textos e Links
———————————————————–*/
h1
{
font-family:Arial;
font-size:45px;
letter-spacing:-5px;
font-weight:bold;
margin:0px;
}
.LinkGeral:link { font-family:Arial; font-size:14px; color:#666; text-decoration:none;}
.LinkGeral:hover { font-family:Arial; font-size:14px; color:#666; text-decoration:underline;}
.LinkGeral:action { font-family:Arial; font-size:14px; color:#666; text-decoration:undeline;}
.LinkGeral:visited { font-family:Arial; font-size:14px; color:#CCC; text-decoration:none;}
[/css]
Listagem 5: Formatando elementos HTML da página de login
O resultado obtido com a correta aplicação dos códigos das Listagens 4 e 5 pode ser visualizado na Figura 7.
Figura 7: View que implementa a tela de login
Implementando a autenticação
Se algum web designer estiver acompanhando este post, até o tópico anterior ficou satisfeito com o conteúdo, já que falamos apenas de aspectos visuais de nossa aplicação. Agora, falaremos do back-end, ou seja, do processo de autenticação de fato.
Existem alguns meios possíveis para se realizar a autenticação de usuários com ASP.NET MVC. No exemplo deste post, utilizaremos um modelo personalizado de autenticação utilizando cookies criptografadas. Para boa parte dos casos testados, esta técnica mostrou-se eficiente e, além disso, com poucas personalizações neste modelo, é possível acrescer características importantes, tais como: validações de cartão de crédito, etc.
Como iremos acessar o banco de dados para verificar a existência do usuário fornecido no formulário, precisamos de uma metodologia de acesso ao mesmo. Neste exemplo, utilizaremos o Entity Framework 4.0, mas você poderia utilizar outro ORM ou métodos do próprio ADO.NET para realizar esta tarefa.
Criaremos também duas classes que atuarão como um repositórios de ações, aqui chamados de “UsersRepository.cs” e “CryptographyRepository.cs“. A utilização de repositórios é uma boa prática, pois, facilita a manutenção do código e, além disso, melhora o design da aplicação.
Como temos um bom caminho ainda para percorrer, vamos a implementação de fato. Iniciaremos pela criação de nosso modelo de dados com EF (Entity Framework). Como já possuímos a base de dados AdventureWorks, o que temos a fazer é ordenar ao EF que faça o mapeamento desta base e nos forneça o acesso a todos os recursos. Assim, na solution explorer, clique com o botão direito sobre a pasta “Models” e, em seguida, selecione a opção “Add” seguida da opção “New item…“. Na janela que se apresenta, clique na guia “Data” à esquerda e, em seguida, selecione a opção “ADO.NET Entity Data Model“. Nomeie o arquivo conforme a necessidade e clique em “Ok”. A Figura 8 ilustra este procedimento.
Figura 8: Adicionando um Entity Data Model ao projeto
Na tela seguinte, escolha a opção “Generate from database” e clique em “Next“, conforme apresenta a Figura 9.
Figura 9: Selecionando a forma de mapeamento
A próxima tela perguntará a respeito da conexão do banco de dados. Se deseja utilizar uma conexão já existente ou se deseja criar uma nova. Nesta tela, você deverá informar também o nome da conexão utilizada. As Figuras 9 e 10 apresentam as opções (sugestivas) para prosseguir com o processo. Em nosso caso, criaremos uma nova conexão, pois ainda não temos uma estabelecida.
Figura 9: Criando e configurando a nova conexão
Figura 10: Finalizando a parametrização dos dados para conexão
Na tela seguinte, as opções apresentadas referem-se aos objetos do banco de dados que queremos que o EF realize o mapeamento. Para este exemplo, estamos interessados apenas na tabela “Person.Contact“, portanto, a selecionaremos e finalizaremos o processo clicando em “Finish“. A Figura 11 apresenta o processo descrito acima.
Figura 11: Selecionando a tabela “Contact” e finalizando o processo
Conforme mencionado anteriormente, trabalharemos com cookies criptografadas no processo de autenticação, assim, o que faremos a seguir é criar o repositório de criptografia (CryptographyRepository.cs) e nele, teremos encapsuladas as operações relacionadas. Assim, vá até a solution explorer, na pasta “Models” e clique com o botão direito sobre a mesma. Selecione a opção “Add” e, em seguida, “class“. Nomeie conforme a necessidade e clique em “Ok”. Substitua o conteúdo da classe gerada, por aquele apresentado pela Listagem 6.
[csharp]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Cryptography;
using System.IO;
using System.Text;
namespace AutenticacaoUsuarioMVC3.Models
{
public class CryptographyRepository
{
private static byte[] chave = { };
private static byte[] iv = { 12, 34, 56, 78, 90, 102, 114, 126 };
private static string chaveCriptografia = “fabricio1234567″;
//Criptografa o Cookie
public static string Criptografar(string valor)
{
DESCryptoServiceProvider des;
MemoryStream ms;
CryptoStream cs; byte[] input;
try
{
des = new DESCryptoServiceProvider();
ms = new MemoryStream();
input = Encoding.UTF8.GetBytes(valor); chave = Encoding.UTF8.GetBytes(chaveCriptografia.Substring(0, 8));
cs = new CryptoStream(ms, des.CreateEncryptor(chave, iv), CryptoStreamMode.Write);
cs.Write(input, 0, input.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
catch (Exception ex)
{
throw ex;
}
}
//Descriptografa o cookie
public static string Descriptografar(string valor)
{
DESCryptoServiceProvider des;
MemoryStream ms;
CryptoStream cs; byte[] input;
try
{
des = new DESCryptoServiceProvider();
ms = new MemoryStream();
input = new byte[valor.Length];
input = Convert.FromBase64String(valor.Replace(” “, “+”));
chave = Encoding.UTF8.GetBytes(chaveCriptografia.Substring(0, 8));
cs = new CryptoStream(ms, des.CreateDecryptor(chave, iv), CryptoStreamMode.Write);
cs.Write(input, 0, input.Length);
cs.FlushFinalBlock();
return Encoding.UTF8.GetString(ms.ToArray());
}
catch (Exception ex)
{
throw ex;
}
}
}
}
[/csharp]
Listagem 6: Adicionando os namespaces necessários
O código apresentado pela Listagem 6 é simples, e dispensa comentários pormenorizados. Assim, ressaltarei apenas os apectos importantes sobre os mesmo. Como o próprio nome sugere, o método “Criptografar” recebe uma string como parâmetro e, utiliza recursos da classe “System.Security.Cryptography” para criptografar a mesma. Os atributos “chave” e “iv” são parâmetros para criar o encriptador, como pode ser visualizado na linha 31. O método “Descriptografar”, como o nome também sugere, desfaz o processo realizado pelo método anterior, isto é, recebe uma string como parâmetro e a descriptografa de acordo com a chave definida.
Agora que possuímos o processo de criptografia pronto, podemos implementar a autenticação dos usuários. Para isso, criaremos o repositório de usuários, seguindo os mesmos procedimentos descritos para criação do repositório de criptografia. Isto feito, o que deve ser realizado é a adição do código apresentado pela Listagem 7 à classe “UsersRepository.cs“.
[csharp]
//Propriedade que verifica se o usuário encontra-se logado.
public static Contact UsuarioLogado
{
get
{
var Usuario = HttpContext.Current.Request.Cookies[“UserCookieAuthentication”];
if (Usuario == null)
{
return null;
}
else
{
string NovoToken = AutenticacaoUsuarioMVC3.Models.CryptographyRepository.Descriptografar(Usuario.Value.ToString());
int IDUsuario;
if (int.TryParse(NovoToken, out IDUsuario))
{
return GetUsuarioByID(IDUsuario);
}
else
{
return null;
}
}
}
}
//Recuperando o usuário pelo ID
public static Contact GetUsuarioByID(int CodigoUsuario)
{
AdventureWorksEntities ContextoUsuario = new AdventureWorksEntities();
var Consulta = (from usuario in ContextoUsuario.Contact
where usuario.ContactID == CodigoUsuario
select usuario).SingleOrDefault();
return Consulta;
}
/// <summary>
/// Com base no Username e no Password, este método autentica o usuário e o direciona para o local correto.
/// </summary>
/// <param name=”_Username”></param>
/// <param name=”_Password”></param>
/// <returns></returns>
public static bool AutenticarUsuario(string _Username, string _Password)
{
//Criando o contexto de dados para autenticação
AdventureWorksEntities ContextoUsuario = new AdventureWorksEntities();
try
{
var RetornoQueryUser = (from u in ContextoUsuario.Contact
where u.EmailAddress == _Username && u.PasswordHash == _Password
select u).SingleOrDefault();
if (RetornoQueryUser == null)
{
return false;
}
else
{
//Criando um objeto cookie
HttpCookie UserCookie = new HttpCookie(“UserCookieAuthentication”);
//Setando o ID do usuário no cookie
UserCookie.Value = AutenticacaoUsuarioMVC3.Models.CryptographyRepository.Criptografar(RetornoQueryUser.ContactID.ToString());
//Definindo o prazo de vida do cookie
UserCookie.Expires = DateTime.Now.AddDays(1);
//Adicionando o cookie no contexto da aplicação
HttpContext.Current.Response.Cookies.Add(UserCookie);
return true;
}
}
catch (Exception)
{
return false;
}
}
}
[/csharp]
Listagem 7: Repositório de usuários
Novamente, um código vale mais que mil palavras. Vamos aos aspectos gerais do código apresentado pela Listagem 7. A classe UsersRepository possui três componentes: uma propriedade do tipo Contact chamada “UsuarioLogado”, um método chamado “GetUsuarioByID” que retorna uma instância de Contact e finalmente, um método de retorno booleano “AutenticarUsuario”. Basicamente, as funções de cada um são descritas a seguir:
- UsuarioLogado: propriedade que verifica se o usuário que está solicitando determinada view já se encontra ou não autenticado.
- GetUsuarioByID: método que recebe um inteiro (que representa o código do usuário) e, caso exista, retorna uma instância de Contact para o objeto chamador.
- AutenticarUsuario: método que recebe o e-mail e a senha do usuário, verifica a existência do mesmo com base nestas informações e, caso exista, retorna true. Caso contrário retorna false.
Pronto. Agora já possuímos nossos repositórios com seus respectivos métodos e a base para a autenticação está pronta. Nos resta agora, implementar a recuperação dos dados e a troca de mensagens entre os objetos, assim, na solution explorer, na pasta Controllers dê um duplo clique sobre o arquivo “HomeController.cs“. Adicione uma nova action “Index” e decore-a com o atributo [HttpPost], conforme apresentado pela Listagem 8.
[csharp]
[HttpPost]
public ActionResult Index(FormCollection frmLogin)
{
string _Username, _Password;
//Recuperando valores do formulário
_Username = frmLogin[“txtUsuario”];
_Password = frmLogin[“txtSenha”];
//Se alguma das informações
if (UsersRepository.AutenticarUsuario(_Username, _Password))
{
return RedirectToAction(“Sucesso”, “Home”);
}
else
{
return RedirectToAction(“Falha”, “Home”);
}
}
[/csharp]
Listagem 8: Implementando a requisição do login
Pronto, nosso processo de autenticação está concluído. Colocando nossa aplicação e testando-a, obtemos os resultados apresentados pelas Figuras 12 e 13.
Figura 12: Fornecendo os dados para teste da autenticação
Figura 13: Sucesso da operação realizada
Bom pessoal, por hoje é isso. Espero que este post possa ajudá-lo de alguma forma em seus projetos futuros com ASP.NET MVC 3. Dúvidas, sugestões e possíveis correções, por favor, envie através do formulário de contato deste site ou através dos comentários deste post.
Grande abraço a todos :-).
Facebook
Twitter
Instagram
LinkedIn
RSS