VB.NET - Formulário de Login II


Eu já tratei do assunto da criação de um formulário de login no artigo : VB.NET -  Criando um formulário de login.  Estou voltando ao tema devido a solicitação de um usuário, e, basicamente irei mostrar como você pode criar um formulário de login com acesso a uma tabela onde estão armazenados os dados : UsuarioID e Senha , que representam respectivamente o nome do usuário e a senha.

A diferença fica por conta da geração do Hash da senha que ficará armazenado no banco de dados. Desta forma a informação fica protegida pois mesmo que alguém consiga ter acesso a tabela de senhas somente terá o hash da senha e não a senha usada.

Repetindo o que já foi dito no artigo - : Gerando Hash e comparando Arquivos.

"Toda vez que o usuário digitar a senha, o sistema deverá aplicar o algoritmo hash na mesma para obter o MD. Se um intruso conseguir acessar o banco de senhas, verá um monte de códigos que não farão sentido e o intruso não terá como aplicar algoritmos de reversão, pois este é um dos princípios do hash - a sua irreversibilidade. "

O projeto é composto de :

1-) Dois formulários :

   

   

2-) Um módulo - Estou usando um módulo para mostrar que não precisamos obrigatoriamente criar um módulo de classe este fim.

        - A classe util - que possui o método estático (shared) GeraHash() , que irá gerar o hash para o texto da senha informada    

Imports System.Security.Cryptography

Imports System.text
 

Module Login

'variáveis públicas

Public g_login As String

Public conString As String

Public DBCon As System.Data.OleDb.OleDbConnection


Public
Class util


Public
Shared Function GeraHash(ByVal texto As String) As
String

'Cria um objeto enconding para assegurar o padrão

'de encondig para o texto origem

Dim Ue As New UnicodeEncoding

'Retorna um byte array baseado no texto origem

Dim ByteSourceText() As Byte = Ue.GetBytes(texto)

'Instancia um objeto MD5

Dim Md5 As New MD5CryptoServiceProvider

'Calcula o valor do hash para o texto origem

Dim ByteHash() As Byte = Md5.ComputeHash(ByteSourceText)

'Converte o valor obtido para o formato string

Return Convert.ToBase64String(ByteHash)

End Function


End
Class


End
Module

 

3-) O banco de dados Acesso.mdb criado no MSAccess contendo a tabela Usuarios com a seguinte estrutura e dados:

A estrutura da tabela Usuários Incluindo um usuário e gerando um hash para senha

O acesso ao banco de dados será feito via DataReader retornando o UsuarioID e Senha.

O código do evento Click associado ao botão Login do formulário frmLogin.vb é o seguinte :

  ' Variavel usada para controlar o número de tentativas de logon do usuário
    Dim iConta As Integer

    'Variável que instancia um objeto do tipo formulário Principal previamente criado
    'e que será carreagdo apos efetuar um logon com sucesso
    Dim frmMain As New Principal

    Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLogin.Click

        'A string e conexão é usada para para descrever o tipo de banco de dados
        'a localização e os quesitos de segurança usados na conexao
        Dim ConString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Password="""";User ID=Admin;Data Source=d:\teste\Acesso.mdb"

        'Cria um novo objeto conenction e atribui a string de conexão acima
        Dim DBCon As New OleDb.OleDbConnection(ConString)

        'a variávael g_login é publica e esta definida no modulo Login.vb
        'é usada para armazeanr o nome do usuário no login e repassar a informação entre os formulários.
        g_login = Me.txtUsuario.Text
        'atribui a senha a variavel strSenha
        Dim strSenha As String = Me.txtSenha.Text
        'se o usuário ou a senha estiverem vazios avisa o usuário
        If g_login = String.Empty Or strSenha = String.Empty Then
            MessageBox.Show("Informação Incompleta. Preencha os campos com o nome do usuário e senha.", "Informação Incompleta")
            Me.txtUsuario.Focus()
            Return
        End If

        'O banco de dados possui dois campos na tabela Usuarios
        '-UsuarioID uma chave primária do tipo texto que armazena o nome do usuário
        '-Senha que é um texto que guarda a senha do usuário
        Dim strsql As String = "SELECT UsuarioID, Senha FROM Usuarios WHERE UsuarioID='" & g_login & "' "

        'define um comando sobe a conexão para selecionar o usuario e a senha 
        Dim cm As New OleDb.OleDbCommand(strsql, DBCon)
        'cria um objeto datareader
        Dim dr As OleDb.OleDbDataReader

        'define variaveis de controle
        Dim valido As Boolean = False
        Dim Flag As Boolean = False

        Try
            'abre a conexao
            DBCon.Open()
            'executa um comando e gera um datareader (dr)
            dr = cm.ExecuteReader
            'se houver dados retornados
            If dr.HasRows Then
                'percorre o datareader
                While dr.Read
                    'se o Hash da senha informada for igual ao hash armazenado no banco de dados define 
                    'a variavel valido como True
                    If util.GeraHash(strSenha) = dr.Item("Senha") Then
                        valido = True
                    End If
                End While
                'define a variavel controle Flag como true
                Flag = True
            End If
            'fecha o datareader
            dr.Close()

            'incrementa o contador de tentativas
            iConta = iConta + 1
            'se a senha é valida exibe o formulário principal
            If valido = True Then
                Me.Hide()
                frmMain.Show()
                'se o numero de tentativas for maior que 3 então avisa ao usuário
            ElseIf iConta > 3 Then
                Me.Text = "Login - Tentativa " & iConta.ToString
                MessageBox.Show(" Você ultrapassou o número de tentativas. Contate o suporte !", "Número de tentativas ultrapassado.")
                Me.Close()
                'se Flag for false então o usuário é inválido
            ElseIf Flag = False Then
                MessageBox.Show("Nome de usuário Inválido, tente novamente ! ", "Informação Inválida")
                Me.txtUsuario.Focus()
                Me.txtUsuario.Text = ""
                Me.txtSenha.Text = ""
                Me.Text = "Login - Tentativa " & iConta.ToString
            Else
                'senha inválida
                MessageBox.Show("Senha Inválida, tente novamente ! ", "Informação Inválida")
                Me.txtSenha.Focus()
                Me.txtSenha.Text = ""
                Me.Text = "Login -  Tentativa " & iConta.ToString
            End If
            'trata as exceções 
        Catch exOledb As OleDb.OleDbException
            MessageBox.Show(exOledb.Message, "Erro de acesso ao Banco de Dados", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Erro genérico", MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
            'se a conexão esta aberta fecha e libera os objetos 
            If DBCon.State = ConnectionState.Open Then
                DBCon.Close()
            End If
            cm = Nothing
            dr = Nothing
            DBCon.Dispose()
            'chama o coletor de lixo
            GC.Collect()
        End Try
    End Sub

Destaques do código acima:

DataReader

A utilização dos objetos
DataReader é uma das maneiras mais fáceis para efetuar a leitura dos dados retornados pelos objetos Command . Eles permitem acessar e percorrer os registros no modo de somente leitura e somente para frente - forward-only . Não oferecem acesso desconectado e não permitem alterar ou atualizar a fonte de dados original, sendo usados para obter rapidamente dados de apenas leitura. Apresentam poucos recursos mas seu desempenho é muito melhor do que o oferecido pelos DataSet.

 

As propriedades e métodos mais usadas dos objetos DataReader são :

  1. FieldCount - informa o número de colunas da linha de dados atual
  2. IsClosed - Indica se o objeto DataReader esta fechado.
  3. RecordsAffected - especifica o número de linhas alteradas , excluídas ou incluídas na execução de uma declaração SQL
  4. Item (n) - obtêm o valor da n-ésima coluna no seu formato nativo.
  5. Close - Método que fecha o objeto
  6. GetName - Método que retorna o nome da n-ésima coluna.
  7. Read - método que permite ao DataReader avançar para o próximo registro
  8. IsDbNull - método que informa se a n-ésima coluna possui um valor nulo.

Para criar um objeto DataReader usamos o método ExecuteReader de um objeto Command . Abaixo um exemplo simples de como fazer isto :

 

Dim leitor As SQLDataReader = cmd.ExecuteReader()

- Para criar um DataReader (OleDbDataReader)  usamos o método ExecuteReader do objeto OleDbCommand, o qual retorna um objeto do tipo OleDbDataReader, o qual baseado na Consulta(strsql) usada com o objeto OleDbCommand retorna os registros encontrados na tabela Usuarios. (Enquanto o OleDbDataReader estiver em uso é necessário ter um objeto do tipo OleDbConnection ativo, i.e, uma conexão com a a base de dados.)

-  A versão 1.1 do .NET Framework trouxe uma nova propriedade chamada HasRows para a classe DataReader, que retorna um valor Booleano indicando se há ou não linhas no DataReader. Se existir é informado True,  caso contrário, False.

Este é um exemplo básico e deve ser melhorado. Que tal implementar a chamada ao frmlogin em uma rotina Sub Main() e isolar a camada de acesso aos dados ?

Pegue o código do projeto aqui : formLogin.zip

Até o próximo artigo VB.NET...

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti