Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

RSS iMasters

[Resolvido] ASP.NET MVC 3: Criando um sistema de autenticação com

Recommended Posts

Se você não é um extraterreste, com certeza já ouviu falar de ASP.NET MVC (caso seja, recomendo a leitura da série introdutória à tecnologia).

 

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 artigo 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.

 

39176.png

 

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.

 

39171.png

 

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.

 

39185.png

 

 

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]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>
<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>

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]O resultado das operações executadas acima, pode ser visualizado na Figura 4.

 

39189.png

 

 

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.

 

39187.png

 

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.

 

39186.png

 

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.

 

@{
   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>

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]O resultado obtido com a correta aplicação dos códigos das Listagens 4 e 5 pode ser visualizado na Figura 7.

 

39183.png

 

 

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.

 

39216.png

 

Na tela seguinte, escolha a opção "Generate from database" e clique em "Next", conforme apresenta a Figura 9.

 

39173.png

 

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.

 

39181.png

 

39178.png

 

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.

 

39180.png

 

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]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]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]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.

 

39169.png

 

39175.png

 

Espero que este artigo 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 artigo.

 

Grande abraço a todos :-).

 

 

 

http://imasters.com.br/artigo/21386/dotnet/aspnet-mvc-3-criando-um-sistema-de-autenticacao-com-cookies-criptografadas

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.