WebMatrix - Criando uma Loja Virtual - Continuando as compras e incluindo a autenticação do cliente - 6


Na  quinta parte deste artigo definimos o processo de compra e permitimos ao cliente selecionar e incluir itens em seu carrinho de compras bem como remover itens do carrinho. Vamos continuar as compras e permitir a verificação e finalização das compras.

Continuando as compras

No artigo anterior terminamos de implementar a remoção de itens na página Carrinho.cshtml e dessa forma os clientes podem com sucesso adicionar e remover itens de seus carrinhos de compras individuais, precisamos agora dar a eles a opção de continuar a fazer compras ou, se o seu carrinho contiver todos os itens desejados, proceder à verificação (checkout) para finalizar o pedido.

Como o carrinho é armazenado na sessão do navegador do usuário, não precisamos passar os dados para a página do check-out, podemos definir estas opções como hiperlinks.

Segue abaixo o código completo da página Carrinho.cshtml com os hiperlinks destacados em azul:

@{
Layout = "~/Shared/Layouts/_Layout.cshtml";
Page.Title = "Carrinho";
// Cria um carrinho vazio na sessão se ele não exitir
if (Session["carrinho"] == null)
{
   Session["carrinho"] = new Carrinho();
}
// Pega o carrinho atual da Sessão
Carrinho carrinho = (Carrinho)Session["carrinho"];

if (IsPost)
{
    if (Request["produtoID"] != null)
    {
       //formulário postado pela página Detalhes do produto 
       var _produtoID = Request["produtoID"];
       var _descricao = Request["descricao"];
       var _preco = Request["preco"];
       carrinho.AdicionarItem(_produtoID.AsInt(), _descricao, _preco.AsDecimal());
    }
    else if (Request["removerIndice"] != null)
    {
        // Formulario postado pelo botão Remover Item do Carrinho
        var removerIndice = Request["removerIndice"].AsInt();
        carrinho.RemoverItem(removerIndice);
    }
}

}

<h2>Carrinho de Compras</h2>

@if(carrinho.Itens.Count() == 0)
{
    <p>Não existe nenhum item no seu carrinho de compras.</p>
}
else
{
  <text>  
    <table id="TabelaCarrinho">
    <tr>
      <th class="produto">Produto</th>
      <th class="descricao">Descricao</th>
      <th class="preco">Preço</th>
      <th>&nbsp;</th>
    </tr>
        
   @{
      // Declara e incializar a variável index i
      int i = 0;
    }
        
    @foreach (var item in carrinho.Itens)
    {
      <tr>
         <td class="produto">@Produtos.GetNomeProdutoPorID(item.ProdutoID)</td>
         <td class="descricao">@item.Descricao</td>
         <td class="preco">R$@item.Preco</td>
        
         <td class="remover">
            <form action="Carrinho" method="post">
               @Html.Hidden("removerIndice", i)
               <input type="submit" value="Remover" />
            </form>
         </td>
      </tr>
        
      //incrementa o indice
      i++;
    }
     <tr class="carrinhoTotal">
       <td colspan="2">&nbsp;</td>
       <td>Total: R$@carrinho.ValorTotal</td>
       <td>&nbsp;</td>
     </tr>
    </table>
    <div id="CarrinhoBotoes">
        <a href="/Default" class="linkButton"><b>Continuar Comprando</b></a>&nbsp;&nbsp;
        <a href="/Checkout" class="linkButton"><b>Realizar o Checkout</b></a>
    </div>
  </text>
}

Executando o projeto e incluindo alguns itens no carrinho teremos o seguinte resultado:

Vamos aplicar um estilo nos hiperlinks que criamos incluindo o código abaixo no arquivo Style.css:

div #carrinhoBotoes {
text-align: center;
margin: 40px 0px 20px 0px;
}
.linkButton {
border: 1px solid #cdcdcd;to yet)
background-color: #efefef;
margin: 0px;
padding: 10px;
}
.linkButton:hover {
background-color: #ddd;
}

O resultado após este ajuste pode ser visto na figura abaixo:

Dessa forma nossa página do carrinho de compras possui todas as opções necessárias ao processo de compra embora ainda falte implementar a página de Checkout.

Criando as contas dos clientes

Quando definimos o processo de compra para o nosso site determinamos que um usuário deve ser autenticado antes que ele possa realizar o checkout. Vamos então implementar esta funcionalidade.

Seria mais fácil permitir que o usuário realizasse o checkout diretamente sem autenticação mas então porque vamos exigir a autenticação ?. Pretendemos com isso obter as seguintes vantagens:

Para inicializar o sistema membership da ASP .NET temos que chamar o método WebSecurity.InitializeDatabaseConnection().

Este método informa ao sistema membership qual banco de dados desejamos usar para armazenar o perfil e informação de membership, qual tabela deve armazenar os dados de perfil de usuário, os nomes das colunas usadas para identificar o ID de usuário único e os campos de senha. Como o nome do usuário deve ser único dentro da tabela e desejamos coletar o endereço de e-mail para uso posterior, faz sentido usar o endereço de e-mail como o nome do usuário em todo o aplicativo.

Vamos incluir um novo arquivo _AppStart.cshtml na raiz do site clicando com o botão direito do mouse sobre a raiz do site e escolhendo a opção New File e o template CSTHML e informando o nome _AppStart.cshtml. A seguir digite o código abaixo neste arquivo:

@ {
   WebSecurity.InitializeDatabaseConnection ("TecnoSiteData","UserProfile", "UserID", "Email", true);
}

Qualquer código declarado dentro do arquivo _AppStart.cshtml será executado quando o site for executado pela primeira vez, tornando-o um local ideal para chamar o método WebSecurity.InitializeDatabaseConnection(), que deve ser chamado antes de qualquer interação com o sistema membership da ASP.NET.

Registrando novas Contas

Agora que inicializamos o sistema de associação que criou as tabelas necessárias em nosso banco de dados precisamos fornecer uma página para permitir que novos usuários sejam cadastrados no site.

Crie uma nova pasta na raiz do site chamado Contas. Para isso clique com o botão direito sobre a raiz do site e selecione New Folder e informe o nome Contas.

Vamos usar essa pasta para nos ajudar a organizar as páginas dentro do nosso site, colocando todas as páginas que contêm funcionalidade de adesão dentro dela. Nesta nova pasta, crie um arquivo chamado Registro.cshtml clicando com o botão direito do mouse sobre a pasta Contas, selecionando New File e o template CSHTML e informando o nome Registro.cshtml.

A listagem abaixo contém o código completo para esta página que implementa o registro de contas:

@{
Layout = "~/Shared/Layouts/_Layout.cshtml";
Page.Title = "Registro";
var email = "";
var senha1 = "";
var senha2 = "";
if(IsPost)
{
    WebSecurity.Logout();
    email = Request["email"];
    password1 = Request["senha1"];
    password2 = Request["senha2"];
    // Validação
    if (email.IsEmpty()) 
    {
        ModelState.AddError("email", "O Email é requerido.");
    }
    if (!Validation.IsValidEmail(email))
    {
        ModelState.AddError("email", "Endereço de Email inválido.");
    }
    if (senha1.IsEmpty()) 
    {
        ModelState.AddError("senha1", "A senha é obrigatória.");
    }
    if(WebSecurity.UserExists(email))
    {
        ModelState.AddError("email", "Já existe uma conta com este nome.");
    }
    if(senha1 != senha2)
    {
        ModelState.AddError("senha1", "As senhas não conferem.");
    }
    // Cria uma Conta
    if(ModelState.IsValid)
    {
        WebSecurity.CreateUserAndAccount(email, senha1, null, false);
        WebSecurity.Login(email, senha1);
        if (Request.QueryString["sender"] != null)
        {
            // Retorna o usuário para a URL enviada na chave “sender” da QueryString
            Response.Redirect(Request.QueryString["sender"]);
        }
        else
        {
            // Retorna o usuário para a home page
            Response.Redirect("~/Default");
        }
    }
   }
}
<h1>Registrar Nova Conta</h1>
<form action="Registro?@Request.QueryString" method="post" class="contaFormulario">
<p>
@Html.Label("Endereço de Email: ", "email")<br />
@Html.TextBox("email", email)
@Html.ValidationMessage("email")
</p>
<p>
@Html.Label("Senha: ", "senha1")<br />
@Html.Password("senha1", senha1)
@Html.ValidationMessage("senha1")
</p>
<p>
@Html.Label("Confirmar a Senha: ", "senha2")<br />
@Html.Password("senha2", senha2)
</p>
<p>
<input type="submit" value="Registrar" />
</p>
</form>

Quando esta página é carregada pela primeira vez (como o resultado de um pedido HTTP GET), um formulário vazio de registro será exibido ao usuário. O formulário de inscrição consiste em uma caixa de texto com o endereço de e-mail e dois campos de senha. Os dois campos de senha são apresentadas para minimizar a possibilidade de erros de digitação de senha sendo submetidos a base de dados.

Quando o usuário enviar o formulário, realizamos o logout de qualquer usuário atual e executamos a validação dos valores do formulário. Esta validação inclui verificações para garantir que nenhum dos campos estejam vazios e os dois campos de senha tenham valores iguais e um usuário com o nome requisitado não exista no banco de dados.

Como estamos usando um endereço de e-mail como nome de usuário nós também precisamos realizar a validação para verificar se o endereço de email está em um formato válido. Para fazer isso vamos criar uma página Validacao.cshtml na pasta App_Code com o seguinte código:

@*Funcoes de Validacao *@
@functions {
@* Comparação *@
public static bool IsEqualTo<T>(T value, T comparator) where T : IComparable
{
    return value.Equals(comparator);
}
public static bool IsGreaterThan<T>(T value, T comparator) where T : IComparable
{
    return value.CompareTo(comparator) > 0;
}
public static bool IsLessThan<T>(T value, T comparator) where T : IComparable
{
    return value.CompareTo(comparator) < 0;
}
public static bool IsGreaterThanOrEqualTo<T>(T value, T comparator) where T : IComparable
{
    return value.CompareTo(comparator) >= 0;
}
public static bool IsLessThanOrEqualTo<T>(T value, T comparator) where T : IComparable
{
    return value.CompareTo(comparator) <= 0;
}
@* Range Validation *@
public static bool IsBetween<T>(T value, T minValue, T maxValue) where T : IComparable
{
    return (value.CompareTo(minValue) >= 0 && value.CompareTo(maxValue) <= 0);
}
@* Pattern Matching *@
public static bool IsNumbersOnly(string value)
{
    string expression = @"^[0-9]+$";
    return System.Text.RegularExpressions.Regex.IsMatch(value, expression);
}
public static bool IsLettersOnly(string value)
{
    string expression = @"^[A-Za-z]+$";
    return System.Text.RegularExpressions.Regex.IsMatch(value, expression);
}
public static bool IsAlphaNumeric(string value)
{
    string expression = @"^[A-Za-z0-9]+$";
    return System.Text.RegularExpressions.Regex.IsMatch(value, expression);
}
public static bool IsValidEmail(string value)
{
    string expression = @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
    @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
    @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
    return System.Text.RegularExpressions.Regex.IsMatch(value, expression);
}
}

Esta biblioteca de validação será usada em todo o nosso site.

Se qualquer uma das validações falhar, as informações de erro relevantes são exibidas ao usuário através do Helper Html.ValidationMessage().

Uma vez que um formulário válido foi enviado com sucesso, a conta é criada, passando o nome de usuário e senha para o método WebSecurity.CreateUserAndAccount() e o usuário estará conectado.

O navegador é então redirecionado para a página padrão ou para uma URL passada através da tecla sender da QueryString. Vamos usar essa chave na QueryString ao registrar diretamente a partir da página de checkout para retornar o usuário.

Vamos adicionar também na página de estilos do site, Style.css, os estilos usados neste processo conforme o código abaixo:

/* Formulario Contas
---------------------------------*/

.contasFormulario label {
font-weight: bold;
padding-right: 5px;
}
.contasFormulario p {
padding: 5px 0px 5px 0px;
}
input[type="password"]
{
border: 1px solid #cdcdcd;
}
/* Validation
---------------------------------*/

.validation-summary-errors,
span.field-validation-error {
color: #FF0000;
}
input.field-validation-error {
border: 1px solid #FF0000;
background-color: #FFCCCC;
}

Para vermos o resultado temos que executar o projeto e digitar na URL /Contas/Registro.cshtml ; o resultado deverá ser o mostrado abaixo:

Se você der uma espiada no banco de dados TecnoSite.sdf , clicando na guia DataBases, verá que foram criadas 3 tabelas referente ao membership que implementamos conforme mostra a figura abaixo:

Criando um Helper para resumo da conta

Vamos adicionar um painel para exibir o resumo da conta do usuário na página de leiaute. Este resumo irá exibir um conteúdo diferente para o usuário dependendo do seu estado atual de autenticação. Se o usuário não estiver logado (usuário anônimo) a resumo da conta irá exibir um link para seu carrinho de compra be como links para login e registro. Se o usuário estiver logado ele verá o seu nome de usuário exibido bem como um link para alterar a senha, um link para o seu carrinho de compras e um link para efetuar o log out.

Vamos implementar todas essas funcionalidades em um Helper e para isso vamos incluir um arquivo chamado MembershipHelpers.cshtml na pasta App_Code incluindo o código abaixo neste arquivo:

@helper ResumoConta()
{
if(WebSecurity.IsAuthenticated) {
  <text>
  Bem-Vindo <a href="@Href("~/Contas/AlterarSenha")">
  @WebSecurity.CurrentUserName
  </a> |
  <a href="@Href("~/Carrinho")">Carrinho</a> |
  <a href="@Href("~/Contas/Logout")">Logout</a>
  </text>
} else {
  <text>
  <a href="@Href("~/Contas/Login")">Login</a> |
  <a href="@Href("~/Carrinho")">Carrinho</a> |
  <a href="@Href("~/Contas/Registro")">Registro</a>
  </text>
 }
}

O código é bem simples e verifica a propriedade WebSecurity.IsAuthenticated para ver se o usuário esta logado exibindo o conteúdo apropriado. O helper renderiza os hyperlinks para algumas páginas que ainda vamos implementar como Login, Logout e AlterarSenha.

Para exibir o helper com o resumo da conta do usuário em cada página vamos chamar o helper a partir da página de leiaute _Layout.cshtml; abra esta página na pasta Shared/Layouts e inclua o código abaixo (destacado em azul) que faz a chamada ao nosso helper criado:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
    <title>TecnoSite - @Page.Title</title>
      <link href="@Href("~/Css/Style.css")" rel="stylesheet" />
        @RenderSection("head", required: false)
</head>
<body>
   <div id="page">
        <div id="header">
           <p class="logo"><a href="@Href("~/")">TecnoSite</a></p>
            <div id=”headerRight”>
                <div id="accountSummary">@MembershipHelpers.ResumoConta()</div>
               <div id="search">@RenderPage("~/Shared/Partials/_Busca.cshtml")</div>
            </div>
        </div>
        <div id="content">
           <div id="categorias">
              @RenderPage("~/Shared/Partials/_Categorias.cshtml")
           </div>
        <div id="main">
             @RenderBody()
        </div>
      </div>
       <div id="footer">
          &copy;@DateTime.Now.Year TecnoSite. All rights reserved.
      </div>
    </div>
</body>
</html>

Vamos posicionar a <div> ResumoConta no topo superior direito da página definindo o seguinte estilo no arquivo CSS/Style.css:

#ResumoConta {
float:right;
margin-top: 10px;
text-align: right;
}

Executando o projeto teremos o seguinte resultado exibindo o painel de resumo da conta do usuário não autenticado:

Não seria legal exibir também o número de itens atuais existente no carrinho de compras do usuário ?

Vamos fazer isso ajustando o helper ResumoConta no arquivo MembershipHelpers.cshtml incluindo o código destacado em azul conforme mostrado a seguir:

@helper ResumoConta()
{
    var carrinhoContadorItens = 0;
    if (Session["carrinho"] != null)
    {
        carrinhoContadorItens = ((Carrinho)Session["carrinho"]).Items.Count;
    }

if(WebSecurity.IsAuthenticated) {
  <text>
  Bem-Vindo <a href="@Href("~/Contas/AlterarSenha")">
  @WebSecurity.CurrentUserName
  </a> |
  <a href="@Href("~/Carrinho")">Carrinho - @carrinhoContadorItens produto(s)</a> |
  <a href="@Href("~/Contas/Logout")">Logout</a>
  </text>
} else {
  <text>
  <a href="@Href("~/Contas/Login")">Login</a> |
  <a href="@Href("~/Carrinho")">Carrinho - @carrinhoContadorItens produto(s)</a> |
  <a href="@Href("~/Contas/Registro")">Registro</a>
  </text>
 }
}

O resultado obtido agora para o usuário não autenticado deverá exibir:

Criando a página de Login

A página de Login será usada para autenticar os usuários e será acessada a partir do painel de resumo da conta do usuário, helper ResumoConta, ou via redirecionamento a partir da página Checkout se o usuário não estiver autenticado.

Selecione a guia Files clique como botão direito sobre a pasta Contas selecionando a opção New File;

Clique no template CSHTML e informe o nome Login.cshtml para criar a página de login na pasta Contas. A seguir defina o código abaixo neste arquivo:

@{
Layout = "~/Shared/Layouts/_Layout.cshtml";
Page.Title = "Login";
  var email = "";
  var senha = "";
  if(IsPost)
  {
    email = Request["email"];
    senha = Request["senha"];
    var lembrarme = Request["lembrarme"].AsBool();
    // Validação
    if (email.IsEmpty()) {
        ModelState.AddError("email", "Nome do usuário não pode estar em branco.");
    }
    if (senha.IsEmpty()) {
        ModelState.AddError("senha", "A senha deve ser informada.");
    }
    // tenta fazer o login
    if(ModelState.IsValid)
    {
       if(WebSecurity.Login(email, senha, lembrarme))
       {
           if (Request.QueryString["sender"] != null)
           {
              Response.Redirect(Request.QueryString["sender"]);
           }
           else
           {
               Response.Redirect("~/Default");
            }
        }
        else
        {
           ModelState.AddFormError("Não foi possível realizar o login.");
        }
     }
  }
}
<h1>Login</h1>
@Html.ValidationSummary(true)
<form action="Login?@Request.QueryString" method="post" class="contasFormulario">
<p>Por favor, realize o login. Se você não possui uma conta faça o registro aqui => <a href="../Contas/Registro?@Request.QueryString">registrar</a>.</p>
<p>
@Html.Label("Email : ", "email")<br />
@Html.TextBox("email", email)
@Html.ValidationMessage("email")
</p>
<p>
@Html.Label("Senha: ", "senha")<br />
@Html.Password("senha")
@Html.ValidationMessage("password")
</p>
<p>
@Html.CheckBox("lembrarme", new { value = "true" })
@Html.Label("Lembrar-me neste computador?", "lembrar-me")
</p>
<p>
<input type="submit" value="Login" />
</p>
<p>
<a href="RedefinirSenha">Esqueceu a senha?</a>
</p>
</form>

Agora ao executar o projeto e clicar no link - Login - do painel de resumo de conta teremos a exibição da página de Login conforme abaixo:

A página de Login possui os campos para informar o usuário (Email) e a senha em duas TextBox, um checkbox Lembrar-me neste computador e um botão para submeter o formulário. A página também contém dois links : uma para registro e outro para recuperar uma senha esquecida.

Quando o formulário for submetido os valores serão validados e se houver algum erro mensagens de erro serão exibidas ao usuário. Se os dados forem válidos será iremos tentar efetuar o login passando os valores do email, da senha e do campo lembrar-me para o método WebSecurity.Login().

Obs: O parâmetro persistCookie para o qual passamos o valor boleano do checkbox lembrarme especifica se o usuário irá persistir o cookie de autenticação além da sessão atual.

Se o login falhar, o método Login() irá retornar um valor false, e vamos adicionar um formulário de erro ao ModelState e reexibir o formulário. Se o login form bem sucedido vamos redirecionar o usuário para a URL passada na chave sender da QueryString se ele existir, caso contrário, vamos retornar para página principal.

Criando a página de Logout

Quando o usuário acessa a página de logout o método WebSecurity.Logout() será chamado e o cookie de autenticação será removido e uma mensagem exibida ao usuário com um link para retornar a página principal.

Clique com o botão direito sobre a pasta Contas e selecione New File e a seguir crie o arquivo Logout.cshtml contendo o seguinte código:

@{
Layout = "~/Shared/Layouts/_Layout.cshtml";
Page.Title = "Log Out";
WebSecurity.Logout();
}
<h1>Log Out</h1>
<p>Você foi desconectado do site.</p>
<p><a href="@Href("~/Default")">Retorna para home page</a></p>

Criando a página para alterar senha

A página para alterar a senha é acessada a partir do painel de resumo de conta (helper ResumoConta).

Clique com o botão direito sobre a pasta Contas e selecione New File e a seguir crie o arquivo AlterarSenha.cshtml contendo o seguinte código:

@{
Layout = "~/Shared/Layouts/_Layout.cshtml";
Page.Title = "Alterar Senha";
if (!WebSecurity.IsAuthenticated)
{
   Response.Redirect("~/Default");
}
var senhaAtual = "";
var novaSenha1 = "";
var novaSenha2 = "";
if(IsPost)
{
    senhaAtual = Request["senhaAtual"];
    novaSenha1 = Request["novaSenha1"];
    novaSenha2 = Request["novaSenha2"];
    // Validação
    if (senhaAtual.IsEmpty()) {
    ModelState.AddError("senhaAtual", "A senha atual deve ser informada.");
    }
    if (novaSenha1.IsEmpty()) {
    ModelState.AddError("novaSenha1", "Obrigatória.");
    }
    if (novaSenha2.IsEmpty()) {
    ModelState.AddError("novaSenha2", "Obrigatória.");
    }
    if(novaSenha1 != novaSenha2)
    {
    ModelState.AddError("novaSenha1", "A senha não confere.");
    }
    // tenta mudar a senha
    if(ModelState.IsValid)
    {
        var currentUser = WebSecurity.CurrentUserName;
        if(WebSecurity.ChangePassword(currentUser, senhaAtual, novaSenha1))
        {
            Response.Redirect("~/Default");
        }
        else
        {
            ModelState.AddFormError("Não foi possível alterar a senha.");
        }
    }
}
}
<h1>Alterar Senha</h1>
@Html.ValidationSummary(true)
<form action="AlterarSenha" method="post" class="contasFormulario">
<p>
@Html.Label("Senha Atual: ", "senhaAtual")<br />
@Html.Password("senhaAtual", senhaAtual)
@Html.ValidationMessage("senhaAtual")
</p>
<p>
@Html.Label("Nova Senha: ", "novaSenha1")<br />
@Html.Password("novaSenha1", novaSenha1)
@Html.ValidationMessage("novaSenha1")
</p>
<p>
@Html.Label("Confirmar a Nova Senha: ", "novaSenha2")<br />
@Html.Password("novaSenha2", novaSenha2)
@Html.ValidationMessage("novaSenha2")
</p>
<p>
<input type="submit" value="Alterar Senha" />
</p>
</form>
</body>

A primeira vez que os usuários acessam a página, como resultado de uma solicitação HTTP GET, eles são apresentados a um formulário contendo três caixas de texto e um botão submit. A primeira caixa de texto exige a informação da senha atual(assim evitamos mudanças de senha mal intencionadas); As outras duas caixas de texto exigem que os usuários digitem uma nova senha duas vezes, o que é feito para evitar erros de digitação.

Quando o formulário é enviado, os valores do formulário são validados e mensagens de validação apropriadas são apresentadas ao usuário, utilizando a página ModelState e o helper Html.ValidationMessage() se necessário.

Se os dados forem validados chamamos o método WebSecurity.ChangePassword, passando o nome do usuário e senha junto com a nova senha a ser armazenada. Se a alteração da senha for bem sucedida, o usuário é enviado para a página principal, caso contrário, uma mensagem de erro é adicionada à página ModelState e o formulário é reexibido.

Esqueceu a senha ?

Para encerrar esta etapa vamos implementar a funcionalidade que trata das senhas esquecidas. Se o usuário esqueceu a senha ele poderá clicar no link Esqueci a Senha na página de Login para requisitar via email a sua senha. A senha será enviada para o seu endereço de email que no nosso caso é o nome do usuário. Neste email ele deverá receber um hiperlink para uma página chamada RedefineSenha.cshtml. Neste hiperlink teremos um token único armazenado na QueryString com uma chave identificada como RedefineSenha. Ao ser enviado para a página RedefinirSenha ele será solicitado a informar uma nova senha e alterando a sua senha no banco de dados.

Afim de enviar o email para redefinir a senha ao usuário primeiro temos que configurar o nosso site para enviar emails. Vamos abrir o arquivo _AppStart.cshtml da raiz do site e incluir a inicialização do WebMail conforme o código destacado abaixo onde você deverá informar os detalhes de sua conta e do seu servidor de email:

@{
   WebSecurity.InitializeDatabaseConnection ("TecnoSite","UserProfile", "UserID", "Email", true);
    WebMail.SmtpServer = "<endereço do servidor smtp>";
    WebMail.SmtpPort = <numero da porta>;
    WebMail.EnableSsl = <true ou false>;
    WebMail.UserName = "<usuário da conta de email>";
    WebMail.From = "<conta de email a partir da qual vamos enviar o email>";
    WebMail.Password = "<senha da conta de email>";
}

Agora vamos criar a página RedefinirSenha.cshtml na pasta Contas definindo o código abaixo neste arquivo:

@{
Layout = "~/Shared/Layouts/_Layout.cshtml";
Page.Title = "Esqueceu a senha";
var email = "";
var mensagem = "";
if(IsPost)
{
   email = Request["email"];
   // Validaçao
   if (email.IsEmpty()) {
     ModelState.AddError("email", "O email tem que ser informado.");
   }
   // Gera e envia o email para redefinir a senha
   if(ModelState.IsValid)
   {
     if(WebSecurity.UserExists(email))
     {
        // Gera o link de confirmação
        var redefineToken = WebSecurity.GeneratePasswordResetToken(email);
        var hostUrl = Request.Url.GetComponents(UriComponents.SchemeAndServer,UriFormat.Unescaped);
        var urlRedefineSenha = hostUrl + "/Contas/RedefineSenha?redefineToken=" + HttpUtility.UrlEncode(redefineToken);
        // Envia o email
        WebMail.Send(to: email, subject: "Tecnosite Redefinição de senha para " + email, body: "Por gentileza acesse <a href='" + urlRedefineSenha + "'>" +
        urlRedefineSenha + "</a> para redefinir a senha de sua conta no site TecnoSite.");
        mensagem = "Um email esta sendo enviado para seu endereço de email registrado em nosso site com o link para redefinir sua senha.";
      }
      else
      {
        mensagem = "Não foi possível localizar sua conta.";
      }
   }
}
}
<h1>Esqueceu a Senha?</h1>
 @if (!mensagem.IsEmpty()) {
   <p>@mensagem</p>
 }
 else
 {
   <form action="RedefinirSenha" method="post" class="contasFormulario">
   <p>Informe o seu email registrado em nosso site para receber o link para redefinir sua senha:</p>
   <p>
   @Html.Label("Email : ", "email")<br />
   @Html.TextBox("email", email)
   @Html.ValidationMessage("email")
   </p>
   <p>
   <input type="submit" value="Redefinir Senha" />
   </p>
   </form>
}

Abaixo vemos a exibição desta página quando digitamos /Contas/RedefinirSenha.cshtml na url do site em execução ou acessando a página de Login e clicando no link 'Esqueceu a senha?":

Após informar o seu email e clicar no botão - Redefinir Senha - iremos verificar se o email existe no banco de dados e em caso positivo vamos gerar o token para redefinição de senha usando o método WebSecurity.GeneratePasswordResetToken(). Este token é armazenado automaticamente pelo método no registro do usuário. Além disso vamos gerar o token para construir a URL para o link de redefinição de senha enviado por email ao usuário. Ao final o email é montado e enviado usando o Helper WebMail e uma mensagem é exibida com as instruções ao usuário para verificar sua caixa de email.

Redefinindo a Senha

Será enviado ao usuário um email contendo um link parecido com : http://localhost:58692/Contas/RedefineSenha?redefineToken=0dogNPAJewCD%2b1MQIe%2fX0Q%3d%3d

O link envia o usuário para a página Contas/RedefineSenha.cshtml que vamos criar a seguir. Esta página contém o formulário com duas caixas de texto para que o usuário informe sua nova senha e um botão submit.

Quando o usuário submeter um formulário válido, será tentada a realização da redefinição da senha passando o token, obtido da chave redefineToken na QueryString e a nova senha para o método WebSecurity.ResetPassword(). Se o token conferir com o armazenado na base de dados a senha é redefinida e uma mensagem de sucesso é exibida ao usuário, caso contrário uma mensagem informando que o processo falhou é exibida.

Vamos criar a página RedefineSenha.cshtml na pasta Contas e digitar neste arquivo o código abaixo:

@{
Layout = "~/Shared/Layouts/_Layout.cshtml";
Page.Title = "Redefine Senha";
var redefineToken = Request["redefineToken"] ?? "";
var message = "";
var novaSenha1 = "";
var novaSenha2 = "";

if(IsPost) {
   novaSenha1 = Request["novaSenha1"];
   novaSenha2 = Request["novaSenha2"];
   // Validação
   if (novaSenha1.IsEmpty()) {
     ModelState.AddError("novaSenha1", "Obrigatório.");
   }
   if (novaSenha2.IsEmpty()) {
     ModelState.AddError("novaSenha2", "Obrigatório.");
   }
   if(novaSenha1 != novaSenha2)
   {
     ModelState.AddError("novaSenha1", "As senhas não conferem.");
   }
   // tenta redefinir a senha
   if(ModelState.IsValid)
   {
      if (WebSecurity.ResetPassword(redefineToken, novaSenha1))
      {
         message = "Senha alterada com sucesso.";
      }
      else
      {
          message = "Não foi possível alterar a senha.";
      }
   }
 }
}
<h1>Redefinir Senha</h1>
@if (!message.IsEmpty()) {
<p>@message</p>
}
else
{
<form action="RedefineSenha" method="post" class="contasFormulario">
@Html.Hidden("redefineToken", redefineToken)
<p>
@Html.Label("Nova Senha: ", "novaSenha1")<br />
@Html.Password("novaSenha1", novaSenha1)
@Html.ValidationMessage("novaSenha1")
</p>
<p>
@Html.Label("Confirma Nova Senha: ", "novaSenha2")<br />
@Html.Password("novaSenha2", novaSenha2)
@Html.ValidationMessage("novaSenha2")
</p>
<p>
<input type="submit" value="Alterar Senha" />
</p>
</form>
}

Abaixo vemos o resultado da exibição da página RedefineSenha.cshtml:

Ufa ! Até que enfim encerramos a implementação do sistema membership do site TecnoSite.

Na próxima fase vamos definir o processo de encerramento das compras ou checkout.

Aguarde a quinta parte do artigo: WebMatrix - Criando uma Loja Virtual - Fazendo o Checkout -  7

Referências:


José Carlos Macoratti