ASP .NET 4.5 Web Forms - Autorizando e registrando o usuário  - VI


Este tutorial descreve como modificar o site criado nos tutoriais anteriores de para incluir a autorização do usuário e o registro.(a implementação do pagamento através de transferências bancárias fica por sua conta)

Obs: Acompanhe todas as partes do curso neste link: http://www.macoratti.net/Cursos/aspn_450.htm

Apenas usuários que estão conectados terão autorização para comprar produtos. O modelo de projeto Web Forms da ASP.NET 4.5 já possui a funcionalidade interna de registro de usuário já inclui muito dos recursos que você precisa.

No final do tutorial, você irá testar o aplicativo selecionando produtos para adicionar ao carrinho de compras, clicar no botão check-out.

Obs: A transferência dos dados para o site de testes do PayPal e a confirmação dos dados de entrega e informações de pagamento com  retorno ao site para confirmar e completar a compra ficará por sua conta.

Obs: A implantação da funcionalidade PayPal não será tratada.

Existem vários processadores de pagamento de terceiros que se especializam em compras on-line com escalabilidade e segurança. Como desenvolvedores ASP.NET você deve considerar as vantagens de se utilizar uma solução de pagamento de terceiros antes de implementar uma solução de compras on-line.

O que você vai aprender:

Este artigo foi integralmente baseado no artigo original : http://www.asp.net/web-forms/tutorials/aspnet-45/getting-started-with-aspnet-45-web-forms/checkout-and-payment-with-paypal (com algumas alterações e portado para a linguagem VB .NET)

Incluindo o rastreamento do pedido

Neste tutorial, você vai criar duas novas classes para rastrear os dados da ordem de criadas por um usuário. As classes irão rastrear os dados sobre informações de entrega, total, compra e confirmação de pagamento.

Em tutoriais anteriores nós já definimos o esquema para categorias, produtos e itens de carrinho de compras, criando as classes Categoria, Produto e CarrinhoItem na pasta Models. Agora vamos adicionar duas novas classes para definir o esquema para o pedido do produto e os detalhes do pedido.

Clique com o botão direito do mouse sobre a pasta Models e selecione Add -> New Item;

Na janela aberta selecione o item Code e a seguir selecione Class;

Informe o nome Pedido.vb e clique no botão Add;

Substitua o código deste arquivo pelo código abaixo:

Imports System.ComponentModel.DataAnnotations
Imports System.Collections.Generic
Imports System.ComponentModel

Public Class Pedido
    Public Property PedidoId() As Integer
        Get
            Return m_PedidoId
        End Get
        Set(value As Integer)
            m_PedidoId = value
        End Set
    End Property
    Private m_PedidoId As Integer

    Public Property PedidoData() As System.DateTime
        Get
            Return m_PedidoData
        End Get
        Set(value As System.DateTime)
            m_PedidoData = value
        End Set
    End Property
    Private m_PedidoData As System.DateTime

    Public Property NomeUsuario() As String
        Get
            Return m_NomeUsuario
        End Get
        Set(value As String)
            m_NomeUsuario = value
        End Set
    End Property
    Private m_NomeUsuario As String

    <Required(ErrorMessage:="O nome é obrigatório")> _
    <DisplayName("Nome")> _
    <StringLength(160)> _
    Public Property Nome() As String
        Get
            Return m_Nome
        End Get
        Set(value As String)
            m_Nome = value
        End Set
    End Property
    Private m_Nome As String

    <Required(ErrorMessage:="O Sobrenome é obrigatório")> _
    <DisplayName("Sobrenome")> _
    <StringLength(160)> _
    Public Property Sobrenome() As String
        Get
            Return m_Sobrenome
        End Get
        Set(value As String)
            m_Sobrenome = value
        End Set
    End Property
    Private m_Sobrenome As String

    <Required(ErrorMessage:="O Endereço é obrigatório")> _
    <StringLength(70)> _
    Public Property Endereco() As String
        Get
            Return m_Endereco
        End Get
        Set(value As String)
            m_Endereco = value
        End Set
    End Property
    Private m_Endereco As String

    <Required(ErrorMessage:="A cidade é obrigatória")> _
    <StringLength(40)> _
    Public Property Cidade() As String
        Get
            Return m_Cidade
        End Get
        Set(value As String)
            m_Cidade = value
        End Set
    End Property
    Private m_Cidade As String

    <Required(ErrorMessage:="O Estado é obrigatório.")> _
    <StringLength(40)> _
    Public Property Estado() As String
        Get
            Return m_Estado
        End Get
        Set(value As String)
            m_Estado = value
        End Set
    End Property
    Private m_Estado As String

    <Required(ErrorMessage:="O código Postal é obrigatório")> _
    <DisplayName("Código Postal")> _
    <StringLength(10)> _
    Public Property CodigoPostal() As String
        Get
            Return m_CodigoPostal
        End Get
        Set(value As String)
            m_CodigoPostal = value
        End Set
    End Property
    Private m_CodigoPostal As String

    <Required(ErrorMessage:="O País é obrigatório")> _
    <StringLength(40)> _
    Public Property Pais() As String
        Get
            Return m_Pais
        End Get
        Set(value As String)
            m_Pais = value
        End Set
    End Property
    Private m_Pais As String

    <StringLength(24)> _
    Public Property Telefone() As String
        Get
            Return m_Telefone
        End Get
        Set(value As String)
            m_Telefone = value
        End Set
    End Property
    Private m_Telefone As String

    <Required(ErrorMessage:="O Email é obrigatório")> _
    <DisplayName("Email")> _
    <RegularExpression("[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}", ErrorMessage:="Email inválido.")> _
    <DataType(DataType.EmailAddress)> _
    Public Property Email() As String
        Get
            Return m_Email
        End Get
        Set(value As String)
            m_Email = value
        End Set
    End Property
    Private m_Email As String

    <ScaffoldColumn(False)> _
    Public Property Total() As Decimal
        Get
            Return m_Total
        End Get
        Set(value As Decimal)
            m_Total = Value
        End Set
    End Property
    Private m_Total As Decimal

    <ScaffoldColumn(False)> _
    Public Property PagamentoTransacaoId() As String
        Get
            Return m_PagamentoTransacaoId
        End Get
        Set(value As String)
            m_PagamentoTransacaoId = value
        End Set
    End Property
    Private m_PagamentoTransacaoId As String

    <ScaffoldColumn(False)> _
    Public Property FoiEnviado() As Boolean
        Get
            Return m_FoiEnviado
        End Get
        Set(value As Boolean)
            m_FoiEnviado = value
        End Set
    End Property
    Private m_FoiEnviado As Boolean

    Public Property PedidoDetalhes() As List(Of PedidoDetalhe)
        Get
            Return m_PedidoDetalhes
        End Get
        Set(value As List(Of PedidoDetalhe))
            m_PedidoDetalhes = value
        End Set
    End Property
    Private m_PedidoDetalhes As List(Of PedidoDetalhe)
End Class

Da mesma forma vamos incluir uma nova classe chamada PedidoDetalhe na pasta Models com o seguinte código:

Imports System.ComponentModel.DataAnnotations

Public Class PedidoDetalhe

    'usando a nova notação das propriedades automáticas
    Public Property PedidoDetalheId As Integer
    Public Property PedidoId As Integer
    Public Property NomeUsuario As String
    Public Property ProdutoId As Integer
    Public Property Quantidade As Integer

    'usando a notação antiga para definir uma propriedade
    Public Property PrecoUnitario() As System.Nullable(Of Double)
        Get
            Return m_PrecoUnitario
        End Get
        Set(value As System.Nullable(Of Double))
            m_PrecoUnitario = value
        End Set
    End Property
    Private m_PrecoUnitario As System.Nullable(Of Double)

End Class

As classes Pedido e PedidoDetalhe contém o esquema para definir as informações do pedido usado para a compra e transporte.

Além disso, vamos precisar atualizar a classe de contexto de banco de dados que gerencia as classes de entidade e que fornece acesso a dados para o banco de dados. Vamos incluir as classes Pedido e PedidoDetalhe na classe ProdutoContexto.

Abra o arquivo ProdutoContexto.vb e altere o seu código incluindo as duas linhas de código destacadas em azul que incluem a definição para a classe Pedido e PedidoDetalhe:

Imports System.Data.Entity

Namespace WingtipToys.Models

    Public Class ProdutoContexto
        Inherits DbContext

        Public Sub New()
            MyBase.New("WingtipToys")
        End Sub

        Public Property Categorias() As DbSet(Of Categoria)
        Public Property Produtos() As DbSet(Of Produto)
        Public Property CarrinhoItens() As DbSet(Of CarrinhoItem)
        Public Property Pedido As DbSet(Of Pedido)
        Public Property PedidoDetalhe As DbSet(Of PedidoDetalhe)

    End Class
End Namespace

O código no arquivo ProdutoContexto.vb adiciona o namespace System.Data.Entity para que você tenha acesso a todo o núcleo funcionalidade do Entity Framework. Esta funcionalidade inclui a capacidade de consultar, inserir, atualizar e excluir dados, trabalhando com objetos fortemente tipados. O código acima adiciona acesso ao Entity Framework para as classes Pedido e PedidoDetalhe.

Adicionando Acesso ao Checkout

A nossa aplicação permite que usuários anônimos escolham e adicionem produtos a um carrinho de compras. No entanto, quando os usuários anônimos optarem por comprar os produtos adicionados ao carrinho de compras, eles devem fazer logon no site. Depois de terem se registrado, eles podem acessar as páginas restritas do aplicação que lidam com os processo de checkout e compra. Estas páginas restritas estão contidas na pasta de checkout da aplicação.

Clique com o botão direito do mouse sobre o nome do projeto e selecione Add -> New Folder;

A seguir informe o nome Checkout para esta nova pasta do projeto;

A seguir clique com o botão direito do mouse sobre a pasta Checkout e selecione Add New Item;

Na janela Add New Item selecione Visual Basic -> Web e escolha o template Web Form using Master Page, informando o nome InicioCheckout.aspx e clicando no botão Add;

Selecione a master page Site.Master e clique em OK;

Da mesma forma, repetindo os procedimentos acima vamos incluir na pasta Checkout as seguintes páginas (todas elas usando o template Web Form using Master Page):

Obs: Estou mostrando como criar as páginas mas não vou implementá-las neste tutorial ficando isso por sua conta.

Vamos agora incluir na pasta Checkout um arquivo Web.Config para restringir o acesso a todas as páginas contidas nesta pasta.

Clique com o botão direito do mouse sobre a pasta Checkout e selecione Add -> New Item;

A seguir selecione Visual Basic -> Web e o template Web Configuration File aceitando o nome Web.Config e clicando no botão Add;

Substitua o código deste arquivo pelo seguinte código XML:

<?xml version="1.0"?>
<configuration>
    <system.web>
      <authorization>
        <deny users="?"/>        
      </authorization>
    </system.web>
</configuration>

O arquivo Web.config especifica que todos os usuários desconhecidos da aplicação devem ter o acesso negado às páginas contidas na pasta Checkout. No entanto, se o usuário possuir uma conta registrada e está logado, ele passa a ser um usuário conhecido e terá acesso às páginas na pasta Checkout.

Permitindo o login a partir de outros site com OpenId e OAuth

A ASP.NET Web Forms oferece opções avançadas para a adesão e autenticação. Essas melhorias incluem os novos providers OAuth e OpenID.

Usando esses provedores, você pode permitir que os usuários façam o login em seu site utilizando as suas credenciais existentes no Facebook, Twitter, Windows Live e Google.

Por exemplo, para fazer login usando uma conta no Facebook, os usuários podem escolher apenas uma opção para o Facebook, que redireciona para a página de login do Facebook onde ele insere suas credenciais de usuário.

Eles podem, então, associar o login com a sua conta do Facebook em seu site. Um aprimoramento relacionado recurso membership da Web Forms ASP.NET é que os usuários podem associar vários logins (incluindo logins de redes sociais), com uma única conta em seu site.

Quando você adiciona um provedor de OAuth (Facebook, Twitter ou Windows Live) para o seu aplicativo ASP.NET Web Forms, você deve definir o valor do ID do aplicativo e um valor secreto da aplicação . Você pode adicionar esses valores no arquivo AuthConfig.vb em sua aplicação Web Forms. Além disso, você deve criar um aplicativo no site externo (Facebook, Twitter ou Windows Live). Ao criar o aplicativo no site externo você pode obter as chaves de aplicativos que você precisa, a fim de chamar o recurso de login por esses sites.

Para sites que usam um provedor de OpenID (Google), você não precisa criar um aplicativo no site externo.

Na janela Solution Explorer localize e abra a pasta App_Start;

Abra o arquivo AuthConfig.vb e descomente a última linha de código que permite usar o OpenID para uma conta do Google:

Agora quando você executar a aplicação você terá a opção de acessar sua conta Google e associar a conta o site a com sua conta Google.

Alterando a funcionalidade de Login

Grande parte da funcionalidade de registro do usuário foi incluído no modelo ASP.NET Web Forms por padrão. Agora vamos modificar as páginas Login.aspx e Register.aspx para chamar o método MigrateCart.

O método MigrateCart associa um novo usuário conectado com um carrinho de compras anônimo. Ao associar o usuário e carrinho de compras,nossa aplicação será capaz de manter o carrinho de compras do usuário entre as visitas.

Na janela Solution Explorer abra a pasta Account e abra a página Login.aspx;

A seguir altere o controle Login conforme a linha de código a seguir:

<asp:Login runat="server" ViewStateMode="Disabled" RenderOuterTable="false" ID="LoginCtrl" OnLoggedIn="LoginCtrl_LoggedIn">

Modifique também o arquivo code-behind Login.aspx.vb incluindo o código destacado em azul :

Public Class Login
    Inherits Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
        RegisterHyperLink.NavigateUrl = "Register.aspx"
        OpenAuthLogin.ReturnUrl = Request.QueryString("ReturnUrl")

        Dim returnUrl = HttpUtility.UrlEncode(Request.QueryString("ReturnUrl"))
        If Not String.IsNullOrEmpty(returnUrl) Then
            RegisterHyperLink.NavigateUrl &= "?ReturnUrl=" & returnUrl
        End If
    End Sub

    Protected Sub LoginCtrl_LoggedIn(sender As Object, e As EventArgs)
        Dim usuarioCarrinhoCompras As New WingtipToys.Logic.CarrinhoActions()
        Dim carrinhoId As String = usuarioCarrinhoCompras.GetCarrinhoId()
        usuarioCarrinhoCompras.MigrateCart(carrinhoId, User.Identity.Name.ToString())
    End Sub
End Class

Por enquanto, vamos ignorar o alerta de que não há uma definição para o método MigrateCart. Vamos definir este método mais adiante.

O controle Login suporta um manipulador OnLoggedIn. Você modificou a marcação do controle Login na página Login.aspx adicionando o atributo OnLoggedIn. Quando um usuário tiver terminado de fazer o logon no site usando o controle Login, o manipulador de eventos no arquivo Login.aspx.vb que aponta para OnLoggedIn, dispara o evento LoginCtrl_LoggedIn.

Quando o manipulador de eventos LoginCtrl_LoggedIn que você adicionou ao Login.aspx.vb é chamado, uma nova instância do carrinho de compras usuariosCarrinhoCompras será criado.

A identificação do carrinho de compras (um GUID) é recuperada e definida para a variável carrinhoId. Em seguida, o método MigrateCart é chamado, passando tanto o carrinhoId e o nome do usuário conectado ao método. Quando o carrinho de compras é migrado, o GUID usado para identificar o carrinho de compras anônimo é substituído pelo nome do usuário.

Além de modificar a página Login.aspx para migrar o carrinho de compras, quando o usuário faz login, vamos modificar também a página Register.aspx para migrar o carrinho de compras quando o usuário cria uma nova conta e faz o login.

Na pasta Account abra o arquivo code-behind Register.aspx.vb;

Modifique o código deste arquivo incluindo o código destacado em azul a seguir:

Ignore o alerta sobre o método MigrateCart e salve o arquivo com as alterações.

Observe que você usou o mesmo código no manipulador de eventos RegisterUser_CreatedUser que você usou no manipulador de eventos LoginCtrl_LoggedIn. Quando o usuário se registrar ou fizer o logon, uma chamada para o método MigrateCart será feita.

Migrando o carrinho de compras

Agora temos os processo de registro e login atualizados, vamos adicionar o código para migrar o carrinho de compras implementando o método MigrateCart.

Abra o arquivo CarrinhoActions.vb da pasta Logic na janela Solution Explorer e inclua o método MigrateCart conforme o código abaixo:

 Public Sub MigrateCart(carrinho_Id As String, userName As String)
            Dim carrinhoCompras = _db.CarrinhoItens.Where(Function(c) c.CarrinhoId = carrinho_Id)
            For Each item As CarrinhoItem In carrinhoCompras
                item.CarrinhoId = userName
            Next
            HttpContext.Current.Session(CarrinhoSessaoChave) = userName
            _db.SaveChanges()
        End Sub

O método usa o MigrateCart usa o carrinhoId existente para encontrar o carrinho de compras do usuário. Em seguida, o código percorre todos os itens do carrinho de compras e substitui a propriedade CarrinhoId (conforme especificado pelo esquema CarrinhoItem) com o registrado em nome do usuário.

Fazendo a integração com o PayPal (Apenas a introdução)

Vou dar apenas a introdução na integração do PayPal sendo que a implementação de todas as classes deverá ficar por sua conta.(Veja o artigo original)

PayPal é uma plataforma de faturamento baseado na web que aceita pagamentos por comerciantes online. A seguir vamos explicar como fazer a integração com o PayPal's Express Checkout na nossa aplicação. O Express Checkout permite que seus clientes usem PayPal para pagar os itens que foram adicionados ao seu carrinho de compras.

Criando uma conta de Testes no PayPal

Para utilizar o ambiente de testes do PayPal, você deve criar uma conta de teste do desenvolvedor. Você vai usar a conta de teste do desenvolvedor para criar uma conta de teste do comprador e uma conta de teste do vendedor. As credenciais da conta de testes do desenvolvedor também permitirá que nossa aplicação exemplo acesse o ambiente de testes do PayPal.

Abra o seu navegador e acesse site: https://developer.paypal.com

Se você não possuir uma conta de desenvolvedor clique no botão: Sign Up Now e siga as instruções;

Após criar sua conta faça o login no site do PayPal para acessar o ambiente de testes.

Para criar uma conta de teste do comprador, procure no Titulo Test Accounts e clique em preconfigured para criar uma conta pre-configurada. Escolha um e-mail fictício para a conta de teste do comprador e uma senha. Note que a conta de e-mail do comprador que você escolher terá uma seqüência gerada pelo PayPal adicionada ao nome da conta.

Clique em Create Account para criar uma conta de teste (buyer);

Clique em preconfigured para criar uma conta de teste para vendedor (seller);

Para criar uma conta de teste do vendedor escolha o tipo de conta do vendedor(Seller). Escolha uma conta de login e senha fictícios. A conta de e-mail vendedor que você escolher irá também ter uma seqüência gerada pelo PayPal adicionada ao nome da conta:

Ao terminar o processo clique na opção Test Accounts do menu SandBox e na coluna Payment Review clique no link Disable para habilitar cada conta:

Após isso clique na opção Home do Menu e a seguir clique na opção API and Payament Card Credentials para visualizar as suas credenciais.

Você vai precisar das credenciais apresentadas (API Username, API Password e Signature) para fazer chamadas da API na nossa aplicação para o ambiente de testes do PayPal.

Adicionar uma classe PayPal e credenciais da API (Apenas a dica de como criar a classe)

Vamos colocar a maior parte do código do PayPal em uma única classe. Essa classe contém os métodos usados para se comunicar com PayPal. Além disso, vamos adicionar as credenciais PayPal a esta classe.

Clique com o botão direito do mouse sobre a pasta Logic e selecione Add -> New Item;

Selecione Visual Basic->Code e o template Class; informe o nome PayPalFunctions.vb e clique no botão Add;

Agora basta você copiar e colar o código exibido no artigo original nesta classe.

Obs:Toda a funcionalidade de implementação do PayPal está descrita no artigo original e que por questão de brevidade eu não vou tratar neste artigo.

Executando nossa aplicação e clicando no link Log in iremos obter a seguinte página;

Nela temos a opção de fazer o login usando a conta local ou a conta do Google:

Nota: Se você estiver sob um proxy poderá ocorrer um erro por falta de credenciais para passar pelo proxy.

Se você usar a conta do Google será redirecionando para uma página solicitando sua permissão:

Se você permitir será autenticado com as credenciais do Google bastando apenas confirmar clicando no botão Log in:

Você será redirecionado para a página Default.aspx onde poderá verificar o usuário que esta logado:

A página referente ao link Registrar é mostrada a seguir :

Para registrar um novo usuário basta preencher o formulário e clicar em Registrar:

O novo usuário estará identificado e pronto para navegar e usar as funcionalidades do nosso site:

No próximo tutorial vamos incluir um perfil de administrador em nosso site e implementar o membership: Criando a área de Administração - VII

Referências:


José Carlos Macoratti