Para que estejam ligadas as informações entre a aplicação e as informações salvas, será criado dentro do SGBD Microsoft SQL Server Management Studio um novo banco de dados, com o nome de ExemploLogin.

Neste banco de dados será criada uma tabela com o nome de Usuario, que vai conter os campos código, login e senha para uma futura autenticação do sistema. Veja o conjunto de instruções descrito na Listagem 1 para o SGBD e executar.


SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = 
OBJECT_ID(N'[dbo].[Usuario]') AND type in (N'U'))
BEGIN
CREATE TABLE [dbo].[Usuario](
      [fun_codigo] [int] IDENTITY(1,1) NOT NULL,
      [fun_login] [nvarchar](50) NULL,
      [fun_senha] [nvarchar](50) NULL,
 CONSTRAINT [PK_Usuario] PRIMARY KEY CLUSTERED 
(
      [fun_codigo] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
END
Listagem 1. Estrutura para a criação da tabela Usuario com seus respectivos campos e tipos

Iniciando o Projeto

Agora iremos dar o início para o projeto, tendo o ambiente de desenvolvimento Microsoft Visual Studio 2010. Com ele aberto, vá ao menu superior FileNewProject e depois selecione a opção do projeto Windows Forms Control Library. Atribua o nome da nova biblioteca de ProjetoServiceDesk e selecione o local onde a aplicação será salva. Depois é só clicar em OK.

É preciso agora criar três pastas: uma com o nome de Controller para controlar as ações, outra com o nome de DAO para a comunicação com o banco de dados e, por fim, uma com o nome de Model para que sejam tratadas e modeladas as informações.

Dentro da pasta Controller será criado um arquivo de classe com o nome FuncionarioController.cs. Já na pasta DAO serão criados dois arquivos de classe com os nomes Banco.cs e FuncionarioBD.cs. Dentro da pasta Model será criado um arquivo de classe com o nome de Funcionario.cs.

Após, será criado um novo projeto (mesmo o projeto anterior estando aberto no Solution Explorer) e os passos serão os mesmos, só que ao invés de ser uma nova biblioteca, será um ASP.NET Web Application com o nome WebExemploLogin.

Por padrão, em algumas versões, o ambiente cria automaticamente algumas pastas e arquivos, então será necessário apagar alguns deles e deixar apenas as pastas Properties (Propriedades), References (Referências de bibliotecas) e Web.config.

Agora serão criados outros três arquivos: Default.aspx (que será a página inicial da aplicação web), Principal.aspx (onde será a página de acesso caso o usuário efetuou o login) e Logout.aspx para que o usuário saia da aplicação.

A estrutura do projeto e dos arquivos criados ficará de acordo com a Figura 1.

Hierarquia dos arquivos dentro dos dois projetos
Figura 1. Hierarquia dos arquivos dentro dos dois projetos

Implementando o Projeto servicedesk

Dentro da classe Banco.cs [DAO] será implementado o código descrito na Listagem 2.


  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Web;
  using System.Data.SqlClient;
  using System.Data;
   
  namespace ProjetoServiceDesk.DAO
  {
      internal class Banco
      {
          private string _strConexao;
          private SqlCommand _comandoSQL;
          protected SqlCommand ComandoSQL
          {
              get { return _comandoSQL; }
              set { _comandoSQL = value; }
          }
          protected Banco()
          {
              _strConexao = @"Data Source=USUARIO-PC;Initial 
              Catalog=ExemploLogin;Integrated Security=True;User 
              Id="";Password="";";
              _conn = new SqlConnection(_strConexao);
              _comandoSQL = new SqlCommand();
              _comandoSQL.Connection = _conn;
          }
          protected Banco(string stringConexao)
          {
              _strConexao = stringConexao;
              _conn = new SqlConnection(_strConexao);
              _comandoSQL = new SqlCommand();
              _comandoSQL.Connection = _conn;
          }
          protected bool AbreConexao(bool transacao)
          {
              try
              {
                  _conn.Open();
                  if (transacao)
                  {
                      _transacao = _conn.BeginTransaction();
                      _comandoSQL.Transaction = _transacao;
                  }
                  return true;
              }
              catch
              {
                  return false;
              }
          }
          protected bool FechaConexao()
          {
              try
              {
                  if (_conn.State == ConnectionState.Open)
                      _conn.Close();
                  return true;
              }
              catch
              {
                  return false;
              }
          }
          protected void FinalizaTransacao(bool commit)
          {
              if (commit)
                  _transacao.Commit();
              else
                  _transacao.Rollback();
              FechaConexao();
          }
          protected int ExecutaComando(bool transacao)
          {
              if (_comandoSQL.CommandText.Trim() == string.Empty)
                  throw new Exception("Não há instrução SQL a ser executada.");
   
              int retorno;
              AbreConexao(transacao);
              try
              {
                  retorno = _comandoSQL.ExecuteNonQuery();
              }
              catch(Exception ex)
              {
                  retorno = -1;
                  throw new Exception("Erro ao executar o comando SQL:", ex);
              }
              finally
              {
                  if (!transacao)
                      FechaConexao();
              }
              return retorno;
          }
          protected int ExecutaComando(bool transacao, out int ultimoCodigo)
          {
              if (_comandoSQL.CommandText.Trim() == string.Empty)
                  throw new Exception("Não há instrução SQL a ser executada.");
   
              int retorno;
              ultimoCodigo = 0;
              AbreConexao(transacao);
              try
              {
                  ultimoCodigo = Convert.ToInt32(_comandoSQL.ExecuteScalar());
                  retorno = 1;
              }
              catch(Exception ex)
              {
                  retorno = -1;
                  throw new Exception("Erro ao executar o comando SQL: ", ex);
              }
              finally
              {
                  if (!transacao)
                      FechaConexao();
              }
              return retorno;
          }
          protected DataTable ExecutaSelect()
          {
              if (_comandoSQL.CommandText.Trim() == string.Empty)
                  throw new Exception("Não há instrução SQL a ser executada.");
   
              AbreConexao(false);
              DataTable dt = new DataTable();
              try
              {
                  dt.Load(_comandoSQL.ExecuteReader());
              }
              catch(Exception ex)
              {
                  dt = null;
                  throw new Exception("Erro ao executar o comando SQL: ", ex);
              }
              finally
              {
                  FechaConexao();
              }
              return dt;
          }
          protected double ExecutaScalar()
          {
              if (_comandoSQL.CommandText.Trim() == string.Empty)
                  throw new Exception("Não há instrução SQL a ser executada.");
   
              AbreConexao(false);
              double retorno;
              try
              {
                  retorno = Convert.ToDouble(_comandoSQL.ExecuteScalar());
              }
              catch(Exception ex)
              {
                  retorno = -1;
                  throw new Exception("Erro ao executar o comando SQL: ", ex);
              }
              finally
              {
                  FechaConexao();
              }
              return retorno;
          }
      }
  }
Listagem 2. Classe Banco.cs responsável por efetuar transações, abrir conexão, fechar conexão e retornar dados do Banco de dados

Nessa classe existe o construtor Banco() que é responsável por conectar com o banco de dados através de uma string de conexão. Nela temos as funções AbreConexao (para abrir conexão com o banco de dados) e FechaConexao (para fechar a conexão). O método FinalizaTransacao() é responsável por finalizar alguma transação atual e o método ExecutaComando() é responsável por executar o comando SQL e retornar se houve ou não êxito na comunicação com o banco de dados. Já os métodos ExecutaSelect() e ExecutaScalar() são responsáveis por executares os comandos SQL retornando valores.

Observação: Dependendo de como foi instalado o SGBD Microsoft SQL Server, a string de conexão pode sofrer alterações.

Dentro da classe Funcionario.cs [Model] será implementado o código descrito na Listagem 3.


  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
   
  namespace ProjetoServiceDesk.Model
  {
      public class Funcionario
      {
          public Funcionario() { _codigo = 0; }
          #region Propriedades do Funcionario
          private int _codigo;
          public int Codigo
          {
              get
              {
                  return _codigo;
              }
              set
              {
                  _codigo = value;
              }
          }
   
          private string _login;
          public string Login
          {
              get { return _login; }
              set { _login = value; }
          }
   
          private string _senha;
          public string Senha
          {
              get { return _senha; }
              set { _senha = value; }
          }
          #endregion
      }
  }
Listagem 3. Classe Funcionario.cs responsável por receber o tipo de informação e enviar o mesmo para o banco de dados

São criadas propriedades para o código, login e senha, a fim de que os dados sejam tratados de acordo com o tipo de cada campo.

Agora dentro da classe FuncionarioBD.cs [Banco] será implementado o código descrito na Listagem 4.


  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using ProjetoServiceDesk.Model;
  using System.Data;
   
  namespace ProjetoServiceDesk.DAO
  {
      internal class FuncionarioBD : Banco
      {
          internal FuncionarioBD() { }
   
          internal Funcionario Autenticar(string login, string senha)
          {
              ComandoSQL.Parameters.Clear();
              ComandoSQL.CommandText = @"select * from USUARIO
                      where fun_login = @login and fun_senha = @senha";
              ComandoSQL.Parameters.AddWithValue("@login", login);
              ComandoSQL.Parameters.AddWithValue("@senha", senha);
   
              DataTable dt = ExecutaSelect();
              if (dt != null && dt.Rows.Count > 0)
              {
                  Funcionario f = new Funcionario();
                  f.Codigo = Convert.ToInt32(dt.Rows[0]["fun_codigo"]);
                  f.Login = dt.Rows[0]["fun_login"].ToString();
                  f.Senha = dt.Rows[0]["fun_senha"].ToString();
                  return f;
              }
              else
                  return null;
          }
      }
  }
Listagem 4. Classe FuncionarioBD.cs responsável por executar a instrução de SQL e retornar dentro de um DataTable as informações retornadas

É criada uma função chamada Autenticar passando por parâmetros o login e senha, onde, através de comando SQL, verifica se ambos estão iguais. O DataTable retorna todas as informações como Código, Login e Senha e, se não tiver algo, retorna nulo.

Finalmente, dentro da classe FuncionarioController.cs [Controller] será implementado o código descrito na Listagem 5.


  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using ProjetoServiceDesk.Model;
  using ProjetoServiceDesk.DAO;
   
  namespace ProjetoServiceDesk.Controller
  {
      public class FuncionarioController
      {
          FuncionarioBD bd = new FuncionarioBD();
   
          public Funcionario Autenticar(string login, string senha)
          {
              if (login != "" && senha.Trim().Length > 0)
                  return new FuncionarioBD().Autenticar(login, senha);
              else
                  return null;
          }
          public FuncionarioController() { }
      }
  }
Listagem 5. Classe FuncionarioController.cs controladora que é responsável por autenticar o usuário

É declarada uma instância referente à classe FuncionarioBD. Além disso, é criada uma função Autenticar, passando por parâmetros o login e a senha. Se o login for diferente de vazio e se a senha tiver tamanho maior que 0, então é executado o método Autenticar da classe FuncionarioBD, senão é retornado nulo.

Implementando a Aplicação Web

Partindo do princípio de que a ideia central desse artigo é criar um sistema de login, até agora meio caminho já foi andado, faltando agora implementar a parte visual e alguns detalhes que visam tornar operacional a aplicação.

Para adicionar aquele projeto que se refere a uma biblioteca DLL para esse projeto web, basta clicar com o botão direito em References, clicar em “Add Reference...” e localizar a pasta onde foi criado o arquivo DLL (geralmente localizado na aba Projects) e adicionar.

No arquivo Default.aspx, na parte [Source] adicione o código descrito na Listagem 6 para agilizar o processo.

 
  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
  Inherits="WebExemploLogin.Default" %>
   
  <!DOCTYPE html>
   
  <html xmlns="http://www.w3.org/1999/xhtml">
  <head runat="server">
      <title></title>
  </head>
  <body>
      <form id="form1" runat="server">
      <div>
      
       <asp:Label ID="Label1" runat="server" Text="Login: "></asp:Label>
   <asp:TextBox ID="txtLogin" runat="server"></asp:TextBox>
          <br />
          <br />
          <asp:Label ID="Label2" runat="server" Text="Senha: "></asp:Label>
          <asp:TextBox ID="txtSenha" runat="server"></asp:TextBox>
          <br />
          <br />
          <asp:Button ID="btnEntrar" runat="server" onclick="btnEntrar_Click" 
              Text="Entrar" />
          <br />
          <br />
          <asp:Label ID="lblMensagem" runat="server" Text="-"></asp:Label>
          <br />
          <br />
      
      </div>
      </form>
  </body>
  </html>
Listagem 6. Página Default.aspx onde está a parte visual e também é a página inicial do sistema

Nesta página existem duas caixas de texto: uma referente a entrada do login e outra para a entrada da senha. Além disso, existe um botão para que o usuário entre no sistema para autenticação e um label para que avise na tela se o usuário informou o login e/ou a senha inválida.

Agora, indo na parte [Design], basta apertar F7 ou clicar com o botão direito e ir para a opção View Code, para que os códigos descritos na Listagem 7 possam ser inseridos.


  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Web;
  using System.Web.UI;
  using System.Web.UI.WebControls;
  using ProjetoServiceDesk.Controller;
  using ProjetoServiceDesk.Model;
   
  namespace WebExemploLogin
  {
      public partial class Default : System.Web.UI.Page
      {
          protected void Page_Load(object sender, EventArgs e)
          {
              if (Request.Cookies["Acesso"] != null && !IsPostBack)
              {
                  txtLogin.Text = Request.Cookies["Acesso"]["funcionario"];
                  txtSenha.Attributes.Add("value", Request.Cookies["Acesso"]["senha"]);
              }
   
              if (Request.QueryString["msg"] != null)
                  lblMensagem.Text = Request.QueryString["msg"];
   
              txtLogin.Focus();
          }
   
          protected void btnEntrar_Click(object sender, EventArgs e)
          {
              lblMensagem.Text = string.Empty;
              if (txtLogin.Text.Trim() != "")
              {
                  Funcionario user = new FuncionarioController()
                  .Autenticar(txtLogin.Text, txtSenha.Text);
                  if (user != null)
                  {
                      Session["autenticado"] = "OK";
                      Session["codigoFuncionario"] = user.Codigo;
                      Session["nomeFuncionario"] = user.Login;
                      Session["senhaFuncionario"] = user.Senha;
   
                      Server.Transfer("Principal.aspx");
                  }
                  else
                      lblMensagem.Text = "Usuário e/ou senha inválida.";
              }
          }
      }
  }
Listagem 7. Códigos referentes aos modos operacionais dos elementos HTML criados e é onde é responsável por realizar as ações dessa página Default.aspx

Dentro do Page_Load são criados dois cookies para que recebam as informações do login e da senha do usuário (funcionário). O label receberá uma mensagem caso haja algum erro na autenticação e o txtLogin receberá o foco.

No botão Entrar, o label recebe vazio, e se o login informado estiver diferente de vazio, é executado o método Autenticar da classe FuncionarioController(), passando por parâmetros o login e senha referentes a classe Funcionario do tipo user. Se o resultado for diferente de nulo, ou seja, se existir, então são criadas as sessões para armazenar os dados e depois é transferido para a página Principal.aspx; senão, aparece uma mensagem de erro.

No arquivo Principal.aspx, que será a página onde o usuário fez o login e com sucesso possa acessar a essa página, na parte [Source] será adicionado o código descrito na Listagem 8.


  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Principal.aspx.cs" 
  Inherits="WebExemploLogin.Principal" %>
   
  <!DOCTYPE html>
   
  <html xmlns="http://www.w3.org/1999/xhtml">
  <head runat="server">
      <title></title>
  </head>
  <body>
      <form id="form1" runat="server">
      <div>
      
          <asp:Label ID="lblUsuario" runat="server" Text="-"></asp:Label>
          <br />
          <br />
          <asp:Button ID="btnSair" runat="server" onclick="btnSair_Click" Text="Sair" />
      
      </div>
      </form>
  </body>
  </html>
Listagem 8. Códigos referentes ao layout da página: Principal.aspx onde são criados um label e um botão para sair do sistema

Agora, na parte do View Code dessa página será introduzida o código descrito na Listagem 9.


  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Web;
  using System.Web.UI;
  using System.Web.UI.WebControls;
   
  namespace WebExemploLogin
  {
      public partial class Principal : System.Web.UI.Page
      {
          public static void VerificaLogin()
          {
              if (HttpContext.Current.Session["autenticado"] == null ||
                  HttpContext.Current.Session["autenticado"].ToString() != "OK")
              {
                  HttpContext.Current.Session.Abandon();
                  HttpContext.Current.Response.Redirect("Default.aspx?msg=Por favor, 
                  autentique-se");
              }
          }
   
          protected void Page_Load(object sender, EventArgs e)
          {
              VerificaLogin();
   
              if (Session["autenticado"] != null && Session["autenticado"]
              .ToString() == "OK")
              {
                  lblUsuario.Text = string.Format("Código: {0}<br/>Nome: 
                  {1}<br/>Senha: {2}",
                      Session["codigoFuncionario"].ToString(),
                      Session["nomeFuncionario"].ToString(),
                      Session["senhaFuncionario"].ToString());
              }
          }
   
          protected void btnSair_Click(object sender, EventArgs e)
          {
              Response.Redirect("Logout.aspx");
          }
      }
  }
Listagem 9. Códigos referentes a página Principal.aspx que se refere a busca de informações para serem mostradas na tela e ao botão de Sair

A função VerificaLogin() é responsável por identificar se houve a autenticação com êxito, e se for diferente de OK, então significa que não houve e a sessão é destruída, retornando uma mensagem para que o usuário autentique-se.

No Page_Load é chamada a função VerificaLogin() e o label criado anteriormente recebe o Código, o Login e a Senha do usuário autenticado.

No botão Sair que é responsável por sair do sistema encerrando a sessão, é chamado a página de Logout.aspx.

E finalmente dentro do View Code do arquivo Logout.aspx, será implementado os códigos descritos na Listagem 9.


  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Web;
  using System.Web.UI;
  using System.Web.UI.WebControls;
   
  namespace ProjetoServiceDeskWeb
  {
      public partial class Logout : System.Web.UI.Page
      {
          public static void VerificaLogin()
          {
              if (HttpContext.Current.Session["autenticado"] == null ||
                  HttpContext.Current.Session["autenticado"].ToString() != "OK")
              {
                  HttpContext.Current.Session.Abandon();
                  HttpContext.Current.Response
                  .Redirect("Default.aspx?msg=Por favor, autentique-se");
              }
          }
   
          protected void Page_Load(object sender, EventArgs e)
          {
              VerificaLogin();
   
              if (Request.Cookies["Acesso"] != null)
                  Response.Cookies["Acesso"].Expires = DateTime.Now.AddDays(-1);
              Session.RemoveAll();
              Session.Abandon();
              Response.Redirect("Default.aspx");
          }
      }
  }
Listagem 9. Códigos responsáveis por buscar através da sessão em andamento os dados e também para encerrar a atual sessão, direcionando para a página Default.aspx

É desenvolvida a mesma função VerificaLogin() e chamada no Page_Load. Se o cookie criado anteriormente com o nome de Acesso for diferente de nulo, então ele é expirado, e a sessão é removida e é direcionado para a página Default.aspx.

Para finalizar o sistema, basta salvar todos os projetos e executar a aplicação com um Ctrl + F5 ou clicando com o botão direito em cima do arquivo Default.aspx e depois clicar em View in Browser.

Se executado no navegador for o Mozilla Firefox, vai aparecer o mesmo que na Figura 2.

Página Default.aspx sendo executada
Figura 2. Página Default.aspx sendo executada

Para fazer testes, basta adicionar algumas informações na tabela Usuario, no SQL Server, como login e senha. Retorne a aplicação e clique no botão Entrar.

Logo, se os dados emitidos forem incorretos, vai aparecer uma mensagem de usuário ou senha inválida, senão a página vai redirecionar para a Principal.aspx, onde vai conter todas as informações cadastradas e também um botão para Sair que encerrará a sessão e retornará para a página Default.aspx.