Cómo... en .NET |
Comprobar usuario y clave usando una base de datosEjemplo para Visual Basic .NET 2003 (.NET 1.1)Publicado el 28/Nov/2006
|
Introducción:En este artículo te muestro cómo verificar si el
nombre y la clave de un usuario son correctos, pero comprobando esos datos
desde una base de datos de SQL Server. En este artículo, el código de ejemplo es para la versión 2003 de Visual Studio .NET (tanto para Visual Basic como para Visual C#), aunque también es válido para Visual Studio 2005, pero en el caso de Visual Basic, el código de la versión 2005 es algo más simple.
¿Qué hace este ejemplo?Primero hay que entrar en situación, así que, te explico qué es lo que hace este ejemplo que te voy a mostrar aquí. El ejemplo es similar al publicado
anteriormente bajo el título:
Iniciar la aplicación solo al
introducir la clave correcta, que como sabrás publiqué en Abril
de este año y del que hay cuatro versiones, según sea para Visual Studio
2003 o 2005 y en esos dos casos, con el ejemplo para Visual Basic y para C#. En este de hoy (del que seguramente también habrá 4 versiones según el lenguaje y la versión de Visual Studio/.NET), es algo parecido a aquél, es decir, solo deja iniciar una aplicación después de comprobar que el usuario y la clave introducidas son correctos. Pero para saber si la clave introducida es correcta, se busca en una base de datos, en este ejemplo, la base de datos es de SQL Server. Aunque te aviso que el código para una base de datos de Access es muy parecido, solo tienes que cambiar los tipos de objetos usados y la cadena de conexión, así que... si no quieres usar una base de datos de SQL Server, tendrás que "currártelo" más... Para que te hagas una idea de qué es lo que hace este código de ejemplo, te muestro una captura de la ventana de comprobación (ver la figura 1).
No te voy a explicar "los pormenores" de lo que hace la aplicación de ejemplo, ya que en lo que realmente me quiero concentrar es en explicarte cómo comprobar si el nombre y la clave introducida son correctas. Si quieres saber esos "intríngulis", sigue el link al artículo anterior que te comenté antes y así sabrás porqué funciona como funciona. Veamos qué es lo que pasa cuando se pulsa en el botón Aceptar, es decir, cuando se ha escrito el nombre del usuario y la clave y se va a a comprobar si son correctos esos datos.
Private Sub btnAceptar_Click( _ ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles btnAceptar.Click If comprobarUsuario(Me.txtUsuario.Text, Me.txtClave.Text) Then Me.DialogResult = DialogResult.OK Else ' Permitir varios intentos veces = veces + 1 If veces < NumeroIntentos Then Label1.Text = "Quedan " & (NumeroIntentos - veces) & " intentos" Exit Sub End If Me.DialogResult = DialogResult.No End If Hide() End Sub
Como puedes ver en el texto resaltado, lo que hago es llamar a una función que es la que se encarga de comprobar si ese nombre de usuario y esa clave son datos correctos. Veamos que hace esa función, ya que lo que se hace en ella es la parte
importante de este artículo.
' Función para comprobar si el acceso es correcto Private Function comprobarUsuario( _ ByVal nombre As String, _ ByVal clave As String) As Boolean ' Conectar a la base de datos Dim cnn As SqlConnection = Nothing ' Try ' Conectar a la base de datos de SQL Server ' (la cadena debe estar inicializada previamente) cnn = New SqlConnection(cadenaCnn) cnn.Open() ' Definir la cadena que vamos a usar para comprobar ' si el usuario y el password son correctos. ' Utilizo parámetros para evitar inyección de código. Dim sel As New System.Text.StringBuilder ' Usando COUNT(*) nos devuelve el total que coincide ' con lo indicado en el WHERE, ' por tanto, si la clave y el usuario son correctos, ' devolverá 1, sino, devolverá 0 sel.Append("SELECT COUNT(*) FROM Usuarios ") sel.Append("WHERE Nombre = @Nombre AND Clave = @Clave") ' Definir el comando que vamos a ejecutar Dim cmd As New SqlCommand(sel.ToString, cnn) ' Creamos los parámetros cmd.Parameters.Add("@Nombre", SqlDbType.NVarChar, 50) cmd.Parameters.Add("@Clave", SqlDbType.NVarChar, 40) ' ' Asignamos los valores recibidos como parámetro cmd.Parameters("@Nombre").Value = nombre cmd.Parameters("@Clave").Value = clave ' ' Ejecutamos la consulta ' ExecuteScalar devuelve la primera columna de la primera fila ' por tanto, devolverá el número de coincidencias halladas, ' que si es 1, quiere decir que el usuario y el password son correctos. Dim t As Integer = CInt(cmd.ExecuteScalar()) ' Cerramos la conexión cnn.Close() ' ' Si el valor devuelto es cero ' es que no es correcto. If t = 0 Then Return False End If Catch ex As Exception MessageBox.Show("ERROR al conectar a la base de datos: " & vbCrLf & _ ex.Message, "Comprobar usuario", MessageBoxButtons.OK, _ MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1) Return False Finally If Not cnn Is Nothing Then cnn.Dispose() End If End Try ' ' Si llega aquí es que todo ha ido bien Return True End Function
Como ya te he comentado, lo que hacemos es comprobar si ese usuario y esa
clave son correctas. Este código "supone" que accedemos a una base de datos que está indicada en la cadena de conexión cadenaCnn, y que en esa base de datos hay una tabla llamada Usuarios que al menos tiene dos campos, uno llamado Nombre que es del tipo nvarchar y que tiene una longitud de 50 caracteres y el otro llamado Clave que también es del tipo nvarchar y con una longitud de 40 caracteres. Nota:
Lo que hago es crear una "consulta" (la cadena select, que es el texto resaltado) en la que le digo a la base de datos que cuente cuantos datos hay que coincidan con lo que le indico. Es decir, que compruebe cuantos usuarios hay que tengan el nombre y la clave que se indican. Como es de suponer, no debemos tener más de un usuario con la misma clave, si ese es el caso... entonces vamos mal... Si ese usuario y esa clave son correctos, esa consulta devolverá un uno y si no son correctos, devolverá cero. En caso de que devuelva UNO es que es correcto, y si devuelve CERO es que no es correcto. Para saber cuantos datos devuelve esa consulta, uso el método ExecuteScalar del objeto SqlCommand, y tal como está en el comentario del código, (y también aquí), ese método devuelve la primera columna de la primera fila de lo indicado en la cadena de selección, y como lo que debe devolver esa cadena de selección es el número de "datos" que coincidan con lo que hay en la parte WHERE, pues resulta que ese valor es en realidad el total de datos, y como te he dicho hace un párrafo, si devuelve CERO es que no existe esa combinación de nombre/clave, por tanto esos datos no son correctos, por tanto, devolvemos un valor FALSO.
Lo que se comprueba es lo que está en la base de datosPues eso, que lo que se comprueba con el código anterior es lo que haya en la base de datos, es decir, en la base de datos el nombre del usuario está tal y como lo indicamos (esto suele ser así), y la clave también está como la indicamos, esto último NO DEBERÍA SER ASÍ, ¿por qué? pues por seguridad, ya que si la clave está en texto "normal", será más fácil "averiguarla". Para saber cómo "complicar" un poco la cosa, sigue leyendo. Guardar los datos de la clave de forma encriptadaUna solución para que el valor de la clave no esté en texto normal, es
encriptándola. ¿Cómo encriptar la clave?Yo tengo una utilidad para generar la clave SHA1 a partir de una cadena, (en la sección de WinFX publiqué la versión de esa utilidad para .NET 3.0 y XAML), y lo que hago es convertir la clave en el valor correspondiente de la encriptación SHA1 y eso es lo que guardo en la base de datos. Si quieres hacer esto mismo con tus claves, el código que te he mostrado antes, al menos el del evento Click del botón, no puedes usarlo así, ya que lo que debes comprobar en la base de datos es el valor SHA1 correspondiente a la clave que hayan escrito en la caja de textos de la clave. Este es el código modificado del evento Click del botón Aceptar, en el que se llama a la función que genera el valor SHA1 de la clave introducida.
Private Sub btnAceptar_Click( _ ByVal sender As Object, _ ByVal e As System.EventArgs) _ Handles btnAceptar.Click ' Convertir a SHA1 la clave introducida Dim claveSHA As String = Me.generarClaveSHA1(Me.txtClave.Text) If comprobarUsuario(Me.txtUsuario.Text, claveSHA) Then Me.DialogResult = DialogResult.OK Else ' Permitir varios intentos veces = veces + 1 If veces < NumeroIntentos Then Label1.Text = "Quedan " & (NumeroIntentos - veces) & " intentos" Exit Sub End If Me.DialogResult = DialogResult.No End If Hide() End Sub
Y este es el código de la función generarClaveSHA1: Private Function generarClaveSHA1(ByVal nombre As String) As String ' Crear una clave SHA1 como la generada por ' FormsAuthentication.HashPasswordForStoringInConfigFile ' Adaptada del ejemplo de la ayuda en la descripción de SHA1 (Clase) Dim enc As New UTF8Encoding Dim data() As Byte = enc.GetBytes(nombre) Dim result() As Byte Dim sha As New SHA1CryptoServiceProvider ' This is one implementation of the abstract class SHA1. result = sha.ComputeHash(data) ' ' Convertir los valores en hexadecimal ' cuando tiene una cifra hay que rellenarlo con cero ' para que siempre ocupen dos dígitos. Dim sb As New StringBuilder For i As Integer = 0 To result.Length - 1 If result(i) < 16 Then sb.Append("0") End If sb.Append(result(i).ToString("x")) Next ' Return sb.ToString.ToUpper End Function Para que ese código te funcione debes tener una importación al espacio de nombres System.Security.Cryptography que es donde se define la clase SHA1CryptoServiceProvider y también a System.Text que es donde se definen las clases StringBuilder y UTF8Encoding.
Espero que todo lo aquí dicho te sea de utilidad y te sirva para hacer eso que querías saber y que tantas veces me han preguntado... Un poco más abajo tienes el código completo de
esta utilidad, en la que hay dos formularios para comprobar la clave, uno
que no usa la clave SHA1 y otro que si lo usa.
Nos vemos.
Los ficheros con el códigoLa utilidad para crear la base de datos y la tabla de usuarios de ejemplo:
El ejemplo completo para comprobar si el usuario y la clave son correctos:
Espacios de nombres usados en el código de este artículo:System.Windows.Forms |