Вы находитесь на странице: 1из 53

Tutorial para la creacin de un sitio Web con autenticacin mediante formulario

Usando varios mtodos para realizar la autenticacin


En este artculo te voy a explicar de forma sencilla (o al menos paso a paso) cmo crear una aplicacin Web que utilice un formulario Web (Web Form) para realizar la autenticacin (o autorizacin) de los usuarios que quieran navegar por el sitio Web que la utilice.
Nota del traductor: (o sea del Guille) En un principio pens usar a lo largo de este artculo la palabra autentificacin como traduccin de authentication, que es como viene en tres de los cuatro diccionarios de ingls/espaol que he consultado, (en el cuarto, el ms antiguo, ni viene), adems de que en el diccionario de la Lengua Espaola, (al menos el que tengo yo), la entrada de autenticar te manda a autentificar. Si bien, comprobando en el diccionario en lnea de la RAE, tanto autenticar como autentificar te mandan a la misma entrada: autenticar. Por otro lado, autentificacin no existe en el diccionario en lnea de la RAE, sin embargo autenticacin si que aparece como: Accin y efecto de autenticar. Adems en la documentacin de Visual Studio .NET utilizan autenticacin o autenticar, as que es posible que los diccionarios de ingls consultados estn equivocados o no estn al da... Por estas razones, y para no "desentonar" demasiado, finalmente he optado por usar autenticar y autenticacin; si eres de los mos y siempre has usado autentificacin para referirte al proceso de "acreditarse" en un sitio Web... ve cambiando el chip... que sino, nos vamos a confundir con tanto juego de palabras... y finalmente esto va a parecer que no es autntico... je, je.

La comprobacin de esa autenticacin la haremos de tres formas: 1- Usando cdigo directo, es decir, en el propio cdigo de la aplicacin tendremos los nombres y las claves.

Nivel de seguridad 0: esto ni se te ocurra hacerlo en una aplicacin "de verdad". 2- Los nombres de los usuarios y las claves estarn en el fichero Web.config. Para mayor nivel de seguridad no guardaremos la clave, sino que guardaremos un valor HASH que nos servir para comprobar si la clave es "buena". Para este caso, necesitaremos una pequea utilidad para generar ese valor HASH. 3- Los nombres y claves se guardan en una base de datos. Para un buen nivel de seguridad, se recomienda que las claves se guarden como valores HASH, no guardadas directamente... el problema en este caso es que ni nosotros podremos saber la clave del usuario, salvo que en lugar de dejar que se genere automticamente usemos una utilidad como la indicada en el punto anterior...

Crear una aplicacin Web con Visual Studio .NET


Empecemos creando una aplicacin Web con Visual Studio .NET, en estos ejemplos he usado la versin 2003 y para el cdigo mostrado en el artculo usar Visual Basic .NET, despus (si el tiempo me lo permite) te mostrar el de C#.

Nota: Aunque he preferido usar el Visual Studio para crear la aplicacin, (es ms cmodo y te permite crear el diseo de los formularios y dems), realmente no es necesario, pero, como te digo, as resultar ms fcil y la gente de Microsoft seguramente seguir poniendo publicidad en mi sitio... je, je.

Los pasos a seguir: - Creacin del proyecto y de la pgina de Login - Crea un nuevo proyecto en Visual Studio, selecciona el lenguaje que quieras (ya te digo que en el artculo te mostrar el cdigo de VB) y elije el de Aplicacin Web. - Te pedir un nombre para crearlo en el localhost, yo he usado pruebaLogin. - Cuando Visual Studio termine de crear el sitio, se mostrar el proyecto "inicial" que el Visual Studio, en la figura 1 podemos ver el explorador de soluciones:

Figura 1. La solucin recin creada - De este proyecto podemos eliminar los ficheros Global.asax y Styles.css (aunque puedes dejar el .css si sueles usar estilos... yo no uso estilos y en este ejemplo lo borrar). - Al fichero WebForm1.aspx le vamos a cambiar el nombre por Login.aspx - Aadimos dos etiquetas, dos cajas de textos y un botn, tal como vemos en la figura 2.

Figura 2. El formulario de Login - La caja superior se llama txtUsuario, la del password: txtPassword y el botn: btnLogin - Selecciona la caja de password y en la ventana de propiedades, asigna a la propiedad TextMode el valor Password, esto har que se no se vea lo que es usuario escribe. Ver figura 3.

Figura 3. Indicar que la caja de textos se usar para introducir una clave - Cada formulario Web (pgina .aspx) realmente tiene asociada una clase (es una clase!), por tanto vamos a hacer que el nombre de la clase del formulario Login.aspx se llame tambin Login, ya que el nombre que tendr ser el que le dio el VS al crearla, es decir, la clase se llama WebForm1 y el queremos que se llame (si es posible) de la misma forma que el formulario. - Lo que debes hacer es mostrar el cdigo, por tanto selecciona el fichero Login.aspx del explorador de soluciones y pulsa F7 o bien pulsa en el primer icono del toolbar (barra de herramientas) que se muestra en la ventana del explorador de soluciones (ver figura 1). - Ahora tendremos a la vista el cdigo de esa pgina Web. Esta es una de las razones por las que es preferible usar el Visual Studio en lugar, de por ejemplo el WebMatrix, las cosas estn en el mismo sitio que en cualquier aplicacin... y es ms intuitivo... (pero este comentario no quita que te muestre despus cmo hacerlo todo "a pelo"). - Seleccionamos la palabra WebForm1 (figura 4) y la cambiamos por Login (figura 5)

Figura 4. Cambiamos el nombre predeterminado...

Figura 5. ...por el mismo que tiene el WebForm: Login

- Ahora vamos a escribir el cdigo para comprobar el nombre del usuario y el password, pero por medio de cdigo. - Antes de nada, vamos a aadir dos nuevas pginas: - Una ser la usada para que el usuario navegue por nuestro sitio, esta pgina la vamos a llamar Default.aspx (que es el nombre normal que usa el VS) - La otra la llamaremos Candemor.aspx (je, je, en honor al Chiquito de la Calz (o Calzada) que es malagueo...), que ser la usada para mostrar al usuario un aviso de que no est autorizado para entrar en el sitio. - Para aadir una nueva pgina, en el men Proyecto, selecciona Agregar Web Forms... esto mostrar un dilogo como el mostrado en la figura 6, escribe el nombre de la pgina (el primer caso: Default)

Figura 6. Aadir un nuevo formulario Web

Nota: Por ahora no te preocupes de lo que haya que mostrar en ese formulario Web. - Aade un nuevo formulario al que le daremos el nombre Candemor. - Ya que tenemos en modo diseo este ltimo formulario, vamos a aadirle una etiqueta y en la propiedad Text escribiremos algo as: "Pecador de la pradera, no ests autorizado a entrar en este sitio". - Cambia el tamao de la fuente para que se vea bien. Ver figura 7. La etiqueta se adaptar al tamao que sea necesario, pero puedes cambiarlo... no te explico como que eso se supone que ya lo sabrs... bueno, vale, usa los cuadritos que hay en cada lado de la etiqueta y juega con ellos...

Figura 7. Propiedades de la etiqueta con texto grande y en negrita

- Muestra el formulario Default (en la ventana del explorador de soluciones, haz dobleclick en Default.aspx (o la seleccionas y pulsas Shift+F7) - Aade una etiqueta al formulario y en el texto le pones: "Bienvenid@ al sitio de tutorialLogin". El tamao de la letra la dejo a tu eleccin. - Ahora s, vamos a escribir el cdigo para validar los usuarios.

Autenticar a los usuarios


Como te coment al principio, vamos a ver tres mtodos (o ejemplos) para comprobar los usuarios que quieren usar nuestro sitio Web.

- Primer ejemplo de autenticacin: Usando cdigo directamente - La comprobacin se har al pulsar en el botn, por tanto vamos a escribir el cdigo dentro del evento Click del botn.

- Haz que se muestre el formulario, pulsa Shift+F7 (maysculas y la tecla F7) si es que ests en la ventana del cdigo o pulsa en el segundo icono del toolbar que hay en el explorador de soluciones. - Selecciona el botn y haz doble click en l, esto crear el evento predeterminado del botn (evento Click) y nos mostrar el cdigo. - Escribe esto (o lo que quieras), dentro de ese mtodo de evento: - Para que no te de error, haz una importacin del espacio de nombres: System.Web.Security Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnLogin.Click ' Prueba 1. Escribiendo el cdigo de comprobacin a "pelo" Dim aceptado As Boolean = False ' Select Case txtUsuario.Text.ToLower Case "pepe" If txtPassword.Text = "Jose" Then aceptado = True End If Case "rafa" If txtPassword.Text = "Rafael" Then aceptado = True End If Case "pili" If txtPassword.Text = "Pilar" Then aceptado = True End If Case "guille" If txtPassword.Text = "Guillermo" Then aceptado = True End If Case Else ' esto no es necesario porque el valor inicial es False, ' pero nunca est de ms, adems que as quin vea el cdigo ' sabe lo que queremos hacer. aceptado = False End Select

' ' si es un usuario de los "previstos" ' redirigirlo a la pgina "principal", por defecto: Default.aspx If aceptado Then FormsAuthentication.RedirectFromLoginPage(txtUsuario.Tex t, False) Else ' sino.. a la de error de login Response.Redirect("Candemor.aspx") End If End Sub Listado 1. El cdigo del botn btnLogin - Lo que hacemos en este cdigo, aunque creo que est claro, es: - Comprobar si el nombre indicado coincide con la clave, para cada usuario tenemos que hacer una comprobacin! - Si el usuario es correcto, asignamos un valor verdadero a la variable aceptado. - En caso contrario (Case Else) asignamos un valor falso. - Comprobamos si aceptamos o no al usuario, de ser s, lo redirigimos a la pgina que solicit, o a Default.aspx si no solicit ninguna, sino que simplemente entr a la de Login, que es lo que har el Visual Studio al ejecutar la aplicacin. - Si no est autorizado lo redirigimos a la pgina de error, en nuestro caso Candemor.aspx, para ello usamos Response.Redirect que es lo que hay que usar en ASP/ASP.NET para mandar a alguien a otra pgina... la que sea, no tiene porqu ser del tipo .aspx. - Vamos a probarlo: - Pulsa F5 (si no has hecho nada raro debera mostrarte la pgina de Login) - Escribe un usuario, por ejemplo "pepe" y en la clave escribe "juan" - Te mandar a la pgina Candemor.aspx - Ahora pulsa en el navegador hacia atrs (o bien cierra la ventana y vuelve a pulsar F5) - En esta ocasin escribe en el nombre "pepe" y en el password escribe "Jose" (con la J en maysculas), pulsa en el botn y te mandar a la pgina Default.aspx.

- Es decir, todo funciona a las mil maravillas... medalla! aplausos!, etc. - Si desde el punto 16.1 no te funciona... es que algo has hecho mal... o bien no has escrito bien el cdigo (el VS te mostrar un mensaje de error indicando ese caso) o tambin puede ser que al "juguetear" hayas cambiado algo ms... por ejemplo qu pgina debe mostrarse. - En este primer ejemplo, la pgina de inicio debe ser Login.aspx, por tanto, si ese es el caso del error, haz lo siguiente: - En el explorador de soluciones selecciona Login.aspx - Pulsa con el botn secundario (el derecho para los diestros) y del men despegable (figura 8), selecciona Establecer como pgina de inicio.

Figura 8. Establecer la pgina de inicio de la aplicacin Web

- Compliquemos un poco la cosa, que esto da la impresin que es coser y cantar (para el que sepa coser y/o cantar). - Ya que sabemos cmo se puede poner una pgina como de inicio, es decir, la que "posiblemente" el usuario indicar en el navegador. Vamos a suponer que el usuario quiere entrar directamente en la pgina Default.aspx. Se supone que para que alguien vea esa pgina debe estar autentificado (o autorizado), a ver que pasa... - Selecciona la pgina Default.aspx en el explorador de soluciones y pulsa con el botn derecho del ratn e indica que esa es la pgina de inicio (figura 8). - Pulsa F5

- Que ha pasado aqu? - Ha entrado sin que hagamos Login... - Pues s... ya que no le hemos dicho en ningn momento que este es un sitio "reservado". - Obliguemos al usuario a "loguearse" (autenticarse) para poder entrar en cualquier pgina. - Cierra el explorer para "terminar" la aplicacin. - Abre el fichero Web.config (doble click en el explorador de soluciones, esto ya no lo vuelvo a repetir) - Busca la "entrada" authentication: <authentication mode="Windows" /> - Sustityelo por esto otro: <authentication mode="Forms"> <forms loginUrl="Login.aspx" /> </authentication> - Guarda los cambios y pulsa F5 para ver que todo funciona bien. - Cachis la mar!... que pasa aqu? - Por qu no pide que el usuario se autentifique? - Porque estamos autorizando a todos los usuarios, por tanto el ASP.NET "piensa" que si estamos autorizando a todos los usuarios para qu pedir que se autentifique... as que los deja pasar. - Pero como de lo que se trata es de que se tenga que autenticar el usuario... veamos nuevamente el fichero Web.config, en esta ocasin busca authorization, estar de esta forma: <authorization> <allow users="*" /> <!-- Permitir a todos los usuarios --> <!-- <allow comas]" por comas]"/> <deny comas]" por comas]"/> --> </authorization> - Cambia todo ese cdigo por este otro (he quitado los comentarios para simplificar): users="[lista de usuarios separados por roles="[lista de funciones separadas users="[lista de usuarios separados por roles="[ lista de funciones separadas

<authorization> <deny users="?" /> <!-- solo los usuarios autentificados --> </authorization> - El deny users="?" le indica a ASP.NET que solo se permitan usuarios autentificados. - A ver si ahora... guarda los cambios y pulsa F5 -BIEN! - Antes de mostrarte la pgina Default.aspx te pide que te autentifiques, para ello te manda a la pgina de Login y si escribes correctamente el nombre y la contrasea te enva a la pgina "solicitada". - El problema es que si no escribes bien la clave... ya no te manda a la pgina de error (Candemore.aspx). - Por qu? - ... pinsalo un poco y ahora te digo la respuesta... - Sita el ratn aqu para ver la respuesta. - Efectivamente esa es la razn... (bueno, vale... te lo digo... que no te da tiempo a leerlo): No se muestra la pgina de error (Candemore.aspx) porque para que el usuario pueda ver cualquier pgina de nuestro sitio (salvo la de Login) debe estar autorizado, y la nica forma de darle autorizacin es que se autentifique. - Para subsanar este problemilla, vamos a aadir una etiqueta a la pgina Login.aspx. - En esta etiqueta (a la que le he dado el nombre LabelAviso) inicialmente mostraremos un mensaje indicando que escriba el nombre y la contrasea para entrar. - Si no es correcto el nombre/password mostraremos el mensaje que pusimos en Candemore.aspx o el que se te ocurra para indicar que no son correctos los datos introducidos, pero no le des pista de dnde se ha equivocado! al enemigo, ni agua! y si es un intruso... cuanto menos sepa mejor. - Eso que te he resaltado en el prrafo anterior es algo que siempre deberas tener en cuenta: no des informacin de los fallos, salvo que ests probndolo t y sepas que nadie ms los ver. - Ya que si, por ejemplo, le dices: "pepe" tu clave no es correcta... el intruso puede llegar a pensar que hay un usuario llamado pepe y podr hacer sus "cbalas" para averiguar la clave... y puede que acierte! - Seguridad ante todo!

- Tenemos que modificar el cdigo del evento Click del botn btnLogin para que en lugar de llamar al formulario Candemore.aspx se muestre el texto: ' sino.. a la de error de login LabelAviso.Text = "Pecador de la pradera, no ests autorizado a entrar en este sitio" - Por supuesto, despus de este cambio, la pgina Candemore.aspx ya no la necesitamos ms. Si quieres puedes borrarla (seleccinala en el explorador de soluciones, usa el botn derecho y selecciona Eliminar) o bien quitarla del proyecto (no se borra), para ello desde el men desplegable, selecciona Excluir del proyecto.

Nota: Si a la etiqueta LabelAviso le has indicado que tenga el texto en negrita y X-Large, pero al probarla ves que te muestra el texto normal... (me acaba de pasar), haz que se muestre el esa pgina en modo formulario (no el cdigo) y pulsa en la ficha HTML (que estar al lado de la de Diseo), eso te mostrar el cdigo HTML usado en la pgina, busca la etiqueta en cuestin, (<asp:label id="LabelAviso" ...) y antes del cierre (/>) aade esto: Font-Bold="True" Font-Size="X-Large" As se mostrar en negrita y en letras grandes.

- Esto sera todo lo que habra que hacer para poder comprobar si el usuario es quin dice ser.

Nota: Si quieres probar, desde "fuera" del Visual Studio .NET, que todo funciona bien, puedes abrir el Explorer y escribir esto en la direccin (suponiendo que el nombre indicado para la aplicacin es pruebaLogin): http://localhost/pruebaLogin/Default.aspx Debes asegurarte de compilar primero la aplicacin (Generar>Generar aplicacin)

- Segundo ejemplo de autenticacin: Indicando los usuarios en Web.config - En el fichero Web.config podemos guardar los nombres de usuarios y las claves, de forma que sea el propio ASP.NET el que se encargue de comprobar si debe o no autorizarlo para entrar en nuestro sitio. - Lo ms recomendable, para que si algn intruso ve ese fichero de configuracin no sepa que claves corresponden a cada usuario, las claves las vamos a guardar como un valor HASH, es decir, un valor numrico que ser nico para cada una de las claves almacenadas. - Para aprovechar el mecanismo de comprobacin que tiene ASP.NET, usaremos los valores HASH producidos por los mtodos de encriptacin SHA1 o MD5. - Antes de entrar en detalles, veamos dnde habra que poner esos nombres y claves. - Como te he comentado antes, esa informacin la escribiremos en el fichero Web.config, concretamente en la seccin authentication. Veamos cmo quedara esa seccin con los nombres usados en el mtodo anterior. <authentication mode="Forms"> <forms loginUrl="Login.aspx"> <credentials passwordFormat="SHA1"> <user name="guille" password="251DBBC3BFFC9445DCE9787E4AA4EA9BD691E705" /> <user name="pepe" password="7550D35A69BE9ACA9AF9C29B880DC3ADEA01BEDC" /> <user name="pili" password="8A42398D66BBD841D44122167025661DEA5EDE28" /> <user name="rafa" password="3E05C90F8530B1BA72519824415D05E08CF5718B" /> </credentials> </forms> </authentication>

- En la seccin credentials el indicamos el tipo de formato usado y despus cada uno de los usuarios, indicando el nombre y el hash del password. - Para usar este tipo de autenticacin, debemos sustituir el cdigo del mtodo Click por este:

Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnLogin.Click Dim aceptado As Boolean = False ' ' Prueba 2. Usando claves encriptadas con SHA1 If FormsAuthentication.Authenticate(txtUsuario.Text, txtPassword.Text) Then aceptado = True Else aceptado = False End If ' ' si es un usuario de los "previstos" ' redirigirlo a la pgina "principal", por defecto: Default.aspx If aceptado Then FormsAuthentication.RedirectFromLoginPage(txtUsuario.Tex t, False) Else ' sino.. a la de error de login LabelAviso.Text = "No ests autorizado a entrar en este sitio" End If End Sub Listado 2. El cdigo para autenticar usando hash encriptadas con SHA1

- Como puedes comprobar es una forma muy cmoda de realizar las comprobaciones, ya que dejamos que sea el propio ASP.NET el que se encargue de comprobarlo. - Es importante saber, que se pueden usar los dos mtodos explicados de forma conjunta. En este caso, si primero comprobamos con las claves Sha1, en la parte Else podemos aadir las comprobaciones "literales" mostradas anteriormente. Pero como te dije, no es conveniente incluir esos nombres directamente en el cdigo, aunque si lo pensamos bien, tampoco habra mayor problema, ya que ese cdigo se incluir solamente en la DLL compilada. - La parte en la que los nombres y claves de los usuarios estn en una base de datos, lo dejaremos para otra ocasin.

Nota del 05/Dic/2006: Aunque no lo he publicado para usar en una aplicacin Web, (pero lo indicado en los siguientes links es igualmente vlido) eso de comprobar el usuario y la clave usando una base de datos lo puedes ver en estos artculos, segn uses Visual Basic o C#: Comprobar usuario y clave usando una base de datos (Visual Basic) Comprobar usuario y clave usando una base de datos (C#)

- Ahora lo que nos interesa es poder generar los valores hash para cada clave que queramos tener. - El cdigo a usar sera el siguiente:

Private Sub btnCrearSHA1_Click(sender As System.Object, e As System.EventArgs) _ Handles btnCrearSHA1.Click txtClaveSHA1.Text = _ FormsAuthentication.HashPasswordForStoringInConfigFile(t xtClave.Text, "SHA1") End Sub Listado 3. Generar el valor hash para una clave indicada

Nota: Si modificas el fichero Web.config fuera del Visual Studio .NET ten en cuenta de guardarlo en formato UTF-8, ya que si has incluido palabras acentuadas, ees, etc., no se vern adecuadamente al abrirlo usando UTF-8 (que es como lo abre el ASP.NET para leer el contenido) e incluso puede producir un error.

En la prxima parte crearemos una pgina Web en la que podremos generar esos valores, pero solamente si el usuario es: "guille".

Tambin aadiremos un control creado por nosotros para que contenga ciertos valores que podrn usar todos los usuarios (normalmente una serie de links que lo redirija a otras pginas de nuestro sitio). Mientras publico la continuacin de este artculo, puedes ir haciendo esto que he comentado, as practicas... je, je, je.

Consideraciones para usar este cdigo (o aplicacin Web)


Todo esto que hemos hecho es una aplicacin Web, es decir el cdigo que tendramos que "publicar" en nuestro sitio Web. Los puntos importantes a tener en cuenta son: 1- La DLL generada debes copiarla en el directorio \BIN del sitio Web. Ese directorio "debe estar forzosamente" en la raz del sitio... no puede estar dentro de otro directorio. Hay que aclarar que realmente la librera si puede estar en otro directorio, pero ese otro directorio debe estar dentro del directorio \bin que forzosamente tiene que estar en el "raz" de nuestro sitio. Para saber cmo incluir la DLL en un subdirectorio del directorio \bin, consulta este artculo de Gustavo Bonansea: Cargar automticamente assemblies fuera del directorio bin 2- El fichero Web.config debes copiarlo en el directorio raz del sitio Web. Esto supone que solamente podrn acceder a tu sitio Web si el usuario est registrado. Por tanto, no uses el fichero Web.config con la informacin de autenticacin salvo que quieras que TODOS los visitantes de tu sitio se tengan que autenticar. 3- Relacionado con el punto anterior, la comprobacin de que los usuarios tienen que hacer login para ver cualquier cosa, solo es cierto si todas las pginas son de ASP.NET (extensin .aspx) 4- En el caso de que quieras tener las dos cosas... pginas "libres" y pginas "privadas" todo esto que te he explicado no te servir de nada... lo siento. 5- La solucin al punto 4 es que crees una "subweb" y en esa subWeb solo admitas a los usuarios que hayas autorizado o bien modificar el fichero Web.config para indicar qu directorios o pginas son las "privadas" o las "pblicas", pero esto seguramente lo veremos en otra

ocasin. 6- Quiero aclararte tambin que lo que debes publicar en el sitio Web son las pginas con extensin .aspx (no las .aspx.vb o .aspx.cs), el mecionado fichero Web.config y la DLL generada.

Bueno, lo dejamos aqu hasta el prximo da en que modifiquemos el cdigo para usar las cosillas que te he indicado anteriormente... y seguramente aadir algunas ms, como por ejemplo usar una clase (o mdulo) para contener cierta informacin global a todos los usuarios. Hasta ese momento, espero que todo esto te vaya siendo de utilidad. Esa es siempre la intencin. Nos vemos. Guillermo Nerja, madrugada del 3 de Marzo de 2005

Cdigo de Visual Basic .NET


El cdigo de Visual Basic .NET es el mostrado en el artculo.

Cdigo de C#

Nota: Este cdigo an no lo he comprobado, pero confo que est bien y que el conversor de VB .NET a C# no me haya fallado.

Cdigo del listado 1 de autenticacin: equivalente al mostrado en esta seccin //-------------------------------------------------------// TODO: Usar esta asignacin en el constructor de la clase: //

// btnLogin.Click += new System.EventHandler(btnLogin_Click); //-------------------------------------------------------private void btnLogin_Click(System.Object sender, System.EventArgs e) { // Prueba 1. Escribiendo el cdigo de comprobacin a "pelo" bool aceptado = false; // switch(txtUsuario.Text.ToLower()){ case "pepe": if( txtPassword.Text == "Jose" ){ aceptado = true; } break; case "rafa": if( txtPassword.Text == "Rafael" ){ aceptado = true; } break; case "pili": if( txtPassword.Text == "Pilar" ){ aceptado = true; } break; case "guille": if( txtPassword.Text == "Guillermo" ){ aceptado = true; } break; default: // esto no es necesario porque el valor inicial es False, // pero nunca est de ms, adems que as quin vea el cdigo // sabe lo que queremos hacer. aceptado = false; break; } // // si es un usuario de los "previstos"

// redirigirlo a la pgina "principal", por defecto: Default.aspx if( aceptado ){ FormsAuthentication.RedirectFromLoginPage(txtUsuario.Tex t, false); }else{ // sino.. a la de error de login Response.Redirect("Candemor.aspx"); } }

Cdigo del listado 2 de autenticacin: equivalente al mostrado en esta seccin //-------------------------------------------------------// TODO: Usar esta asignacin en el constructor de la clase: // // btnLogin.Click += new System.EventHandler(btnLogin_Click); //-------------------------------------------------------private void btnLogin_Click(System.Object sender, System.EventArgs e) { bool aceptado = false; // // Prueba 2. Usando claves encriptadas con SHA1 if( FormsAuthentication.Authenticate(txtUsuario.Text, txtPassword.Text) ){ aceptado = true; }else{ aceptado = false; } // // si es un usuario de los "previstos" // redirigirlo a la pgina "principal", por defecto: Default.aspx if( aceptado ){ FormsAuthentication.RedirectFromLoginPage(txtUsuario.Tex t, false);

}else{ // sino.. a la de error de login LabelAviso.Text = "No ests autorizado a entrar en este sitio"; } }

Cdigo del listado 3 para generar los valores hash de los passwords: //-------------------------------------------------------// TODO: Usar esta asignacin en el constructor de la clase: // // btnCrearSHA1.Click += new System.EventHandler(btnCrearSHA1_Click); //-------------------------------------------------------private void btnCrearSHA1_Click(System.Object sender, System.EventArgs e) { txtClaveSHA1.Text = FormsAuthentication.HashPasswordForStoringInConfigFile(t xtClave.Text, "SHA1"); }

Comprobar usuario y clave usando una base de datos


Ejemplo para Visual Basic .NET 2003 (.NET 1.1)
En este artculo te muestro cmo verificar si el nombre y la clave de un usuario son correctos, pero comprobando esos datos desde una base de datos de SQL Server. Introduccin:
En este artculo te muestro cmo verificar si el nombre y la clave de un usuario son correctos, pero comprobando esos datos desde una base de datos de SQL Server. Tambin te dejo un programa que crea la base de datos y la tabla de ejemplo, adems de aadir 4 usuarios de prueba, dos de ellos con las claves guardadas de forma normal y los otros dos en los que las claves se han guardado usando SHA1, para que de esa forma no se guarde en la base de datos el texto "normal". En este artculo, el cdigo de ejemplo es para la versin 2003 de Visual Studio .NET (tanto para Visual Basic como para Visual C#), aunque tambin es vlido para Visual Studio 2005, pero en el caso de Visual Basic, el cdigo de la versin 2005 es algo ms simple.

Qu hace este ejemplo?


Primero hay que entrar en situacin, 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 ttulo: Iniciar la aplicacin solo al introducir la clave correcta, que como sabrs publiqu en Abril de este ao y del que hay cuatro versiones, segn sea para Visual Studio 2003 o 2005 y en esos dos casos, con el ejemplo para Visual Basic y para C#. No te pongo los cuatro links para no "llenar" demasiado esto, pero pulsando en el link anterior tendrs acceso a las 4 versiones de ese artculo. En este de hoy (del que seguramente tambin habr 4 versiones segn el lenguaje y la versin de Visual Studio/.NET), es algo parecido a aqul, es decir, solo deja iniciar una aplicacin despus 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 cdigo para una base de datos de Access es muy parecido, solo tienes que cambiar los tipos de objetos usados y la cadena de conexin, as que... si no quieres usar una base de datos de SQL Server, tendrs que "currrtelo" ms...

Para que te hagas una idea de qu es lo que hace este cdigo de ejemplo, te muestro una captura de la ventana de comprobacin (ver la figura 1).

Figura 1. El formulario de login (diseo)

No te voy a explicar "los pormenores" de lo que hace la aplicacin de ejemplo, ya que en lo que realmente me quiero concentrar es en explicarte cmo comprobar si el nombre y la clave introducida son correctas. Si quieres saber esos "intrngulis", sigue el link al artculo anterior que te coment antes y as sabrs porqu funciona como funciona. Veamos qu es lo que pasa cuando se pulsa en el botn 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

comprobarUsuario(Me.txtUsuario.Text, Me.txtClave.Text) Then


If 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 funcin que es la que se encarga de comprobar si ese nombre de usuario y esa clave son datos correctos. Veamos que hace esa funcin, ya que lo que se hace en ella es la parte importante de este artculo. Primero veamos el cdigo y ahora te explico un poco ms de lo que ya explican los comentarios que es lo que se hace en esa funcin.

' Funcin 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 parmetros para evitar inyeccin de cdigo. 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 parmetros cmd.Parameters.Add("@Nombre", SqlDbType.NVarChar, 50)

cmd.Parameters.Add("@Clave", SqlDbType.NVarChar, 40) ' ' Asignamos los valores recibidos como parmetro 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 nmero 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 conexin 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. Tanto el nombre del usuario como la clave, los pasamos como parmetros de la funcin. Y se buscarn en la base de datos tal y como los pasemos a esa funcin. Para no complicarte porqu te digo esto, sigue leyendo y al final te lo aclaro.

Este cdigo "supone" que accedemos a una base de datos que est indicada en la cadena de conexin 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 tambin es del tipo nvarchar y con una longitud de 40 caracteres.

Nota: Por supuesto, para tu caso concreto tendrs que cambiar esos valores por los adecuados, pero eso... debes saber hacerlo t!

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 ms 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 mtodo ExecuteScalar del objeto SqlCommand, y tal como est en el comentario del cdigo, (y tambin aqu), ese mtodo devuelve la primera columna de la primera fila de lo indicado en la cadena de seleccin, y como lo que debe devolver esa cadena de seleccin es el nmero 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 prrafo, si devuelve CERO es que no existe esa combinacin 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 datos


Pues eso, que lo que se comprueba con el cdigo 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 tambin est como la indicamos, esto ltimo NO DEBERA SER AS, por qu? pues por seguridad, ya que si la clave est en texto "normal", ser ms fcil "averiguarla". Para saber cmo "complicar" un poco la cosa, sigue leyendo.

Guardar los datos de la clave de forma encriptada


Una solucin para que el valor de la clave no est en texto normal, es encriptndola. Yo suelo guardar las claves en formato SHA1 al estilo de como lo hace el propio ASP.NET. Qu consigo con esto? Pues no dejar las claves como texto normal y corriente, sino como una ristra de 40 valores hexadecimales, que no permitan saber que clave es.

Cmo encriptar la clave?


Yo tengo una utilidad para generar la clave SHA1 a partir de una cadena, (en la seccin de WinFX publiqu la versin de esa utilidad para .NET 3.0 y XAML), y lo que hago es convertir la clave en el valor correspondiente de la encriptacin SHA1 y eso es lo que guardo en la base de datos. Si quieres hacer esto mismo con tus claves, el cdigo que te he mostrado antes, al menos el del evento Click del botn, 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 cdigo modificado del evento Click del botn Aceptar, en el que se llama a la funcin 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 cdigo de la funcin 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 descripcin 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 dgitos. 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 cdigo te funcione debes tener una importacin al espacio de nombres System.Security.Cryptography que es donde se define la clase SHA1CryptoServiceProvider y tambin 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 queras saber y que tantas veces me han preguntado... Un poco ms abajo tienes el cdigo 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. Tambin te dejo una utilidad para crear la base de datos de ejemplo y la tabla Usuarios con cuatro valores, dos de ellos usando texto normal y otros dos con las mismas claves, pero guardadas como una ristra de valores que corresponden con la cadena generada por la funcin generarClaveSHA1.

Nos vemos. Guillermo

Los ficheros con el cdigo


La utilidad para crear la base de datos y la tabla de usuarios de ejemplo: crearBaseEjemploClaves_SQL.rar 23.7 KB (MD5: F61A36A495989F0961C12700A21DEE75) El ejemplo completo para comprobar si el usuario y la clave son correctos: formLoginBaseDatos_vb.rar 15.0 KB (MD5: 7B7D105CCB15EFE35379E34716648609)

Espacios de nombres usados en el cdigo de este artculo:


System.Windows.Forms System.Drawing System.Data.SqlClient System.Security.Cryptography System.Text

Comprobar usuario y clave usando una base de datos

Ejemplo para Visual C# 2003 (.NET 1.1)


En este artculo te muestro cmo verificar si el nombre y la clave de un usuario son correctos, pero comprobando esos datos desde una base de datos de SQL Server. Introduccin:
En este artculo te muestro cmo verificar si el nombre y la clave de un usuario son correctos, pero comprobando esos datos desde una base de datos de SQL Server. Tambin te dejo un programa que crea la base de datos y la tabla de ejemplo, adems de aadir 4 usuarios de prueba, dos de ellos con las claves guardadas de forma normal y los otros dos en los que las claves se han guardado usando SHA1, para que de esa forma no se guarde en la base de datos el texto "normal". En este artculo, el cdigo de ejemplo es para la versin 2003 de Visual Studio .NET (tanto para Visual Basic como para Visual C#), aunque tambin es vlido para Visual Studio 2005, pero en el caso de Visual Basic, el cdigo de la versin 2005 es algo ms simple.

Qu hace este ejemplo?


Primero hay que entrar en situacin, 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 ttulo: Iniciar la aplicacin solo al introducir la clave correcta, que como sabrs publiqu en Abril de este ao y del que hay cuatro versiones, segn sea para Visual Studio 2003 o 2005 y en esos dos casos, con el ejemplo para Visual Basic y para C#. No te pongo los cuatro links para no "llenar" demasiado esto, pero pulsando en el link anterior tendrs acceso a las 4 versiones de ese artculo. En este de hoy (del que seguramente tambin habr 4 versiones segn el lenguaje y la versin de Visual Studio/.NET), es algo parecido a aqul, es decir, solo deja iniciar una aplicacin despus 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 cdigo para una base de datos de Access es muy parecido, solo tienes que cambiar los tipos de objetos usados y la cadena de conexin, as que... si no quieres usar una base de datos de SQL Server, tendrs que "currrtelo" ms... Para que te hagas una idea de qu es lo que hace este cdigo de ejemplo, te muestro una captura de la ventana de comprobacin (ver la figura 1).

Figura 1. El formulario de login (diseo)

No te voy a explicar "los pormenores" de lo que hace la aplicacin de ejemplo, ya que en lo que realmente me quiero concentrar es en explicarte cmo comprobar si el nombre y la clave introducida son correctas. Si quieres saber esos "intrngulis", sigue el link al artculo anterior que te coment antes y as sabrs porqu funciona como funciona. Veamos qu es lo que pasa cuando se pulsa en el botn 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 void btnAceptar_Click(object sender, System.EventArgs e) {

if( comprobarUsuario(this.txtUsuario.Text, this.txtClave.Text) )


{ this.DialogResult = DialogResult.OK; } else { // Permitir varios intentos veces = veces + 1; if( veces < NumeroIntentos ) { Label1.Text = "Quedan " + (NumeroIntentos - veces) + " intentos"; return; } this.DialogResult = DialogResult.No; } Hide(); }

Como puedes ver en el texto resaltado, lo que hago es llamar a una funcin que es la que se encarga de comprobar si ese nombre de usuario y esa clave son datos correctos. Veamos que hace esa funcin, ya que lo que se hace en ella es la parte importante de este artculo. Primero veamos el cdigo y ahora te explico un poco ms de lo que ya explican los comentarios que es lo que se hace en esa funcin.

private bool comprobarUsuario(string nombre, string clave) {

// Conectar a la base de datos SqlConnection cnn = null; // 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 parmetros para evitar inyeccin de cdigo. System.Text.StringBuilder sel = 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 SqlCommand cmd = new SqlCommand(sel.ToString(), cnn); // Creamos los parmetros cmd.Parameters.Add("@Nombre", SqlDbType.NVarChar, 50); cmd.Parameters.Add("@Clave", SqlDbType.NVarChar, 40); // // Asignamos los valores recibidos como parmetro 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 nmero de coincidencias halladas, // que si es 1, quiere decir que el usuario y el password son correctos. int t = Convert.ToInt32(cmd.ExecuteScalar()); // Cerramos la conexin cnn.Close(); // // Si el valor devuelto es cero // es que no es correcto. if( t == 0 ) { return false; }

} catch(Exception ex) { MessageBox.Show("ERROR al conectar a la base de datos: \n" + ex.Message, "Comprobar usuario", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); return false; } finally { if( cnn != null ) { cnn.Dispose(); } } // // Si llega aqu es que todo ha ido bien return true; }

Como ya te he comentado, lo que hacemos es comprobar si ese usuario y esa clave son correctas. Tanto el nombre del usuario como la clave, los pasamos como parmetros de la

funcin. Y se buscarn en la base de datos tal y como los pasemos a esa funcin. Para no complicarte porqu te digo esto, sigue leyendo y al final te lo aclaro. Este cdigo "supone" que accedemos a una base de datos que est indicada en la cadena de conexin 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 tambin es del tipo nvarchar y con una longitud de 40 caracteres.

Nota: Por supuesto, para tu caso concreto tendrs que cambiar esos valores por los adecuados, pero eso... debes saber hacerlo t!

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 ms 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 mtodo ExecuteScalar del objeto SqlCommand, y tal como est en el comentario del cdigo, (y tambin aqu), ese mtodo devuelve la primera columna de la primera fila de lo indicado en la cadena de seleccin, y como lo que debe devolver esa cadena de seleccin es el nmero 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 prrafo, si devuelve CERO es que no existe esa combinacin 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 datos


Pues eso, que lo que se comprueba con el cdigo 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 tambin est como la indicamos, esto ltimo NO DEBERA SER AS, por qu? pues por seguridad, ya que si la clave est en texto "normal", ser ms fcil "averiguarla". Para saber cmo "complicar" un poco la cosa, sigue leyendo.

Guardar los datos de la clave de forma encriptada


Una solucin para que el valor de la clave no est en texto normal, es encriptndola. Yo suelo guardar las claves en formato SHA1 al estilo de como lo hace el propio ASP.NET. Qu consigo con esto?

Pues no dejar las claves como texto normal y corriente, sino como una ristra de 40 valores hexadecimales, que no permitan saber que clave es.

Cmo encriptar la clave?


Yo tengo una utilidad para generar la clave SHA1 a partir de una cadena, (en la seccin de WinFX publiqu la versin de esa utilidad para .NET 3.0 y XAML), y lo que hago es convertir la clave en el valor correspondiente de la encriptacin SHA1 y eso es lo que guardo en la base de datos. Si quieres hacer esto mismo con tus claves, el cdigo que te he mostrado antes, al menos el del evento Click del botn, 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 cdigo modificado del evento Click del botn Aceptar, en el que se llama a la funcin que genera el valor SHA1 de la clave introducida.

private void btnAceptar_Click(object sender, System.EventArgs e) { // Convertir a SHA1 la clave introducida

string claveSHA = this.generarClaveSHA1(this.txtClave.Text); if( comprobarUsuario(this.txtUsuario.Text, claveSHA) )


{ this.DialogResult = DialogResult.OK; } else { // Permitir varios intentos veces = veces + 1; if( veces < NumeroIntentos ) { Label1.Text = "Quedan " + (NumeroIntentos - veces) + " intentos"; return; } this.DialogResult = DialogResult.No; } Hide(); }

Y este es el cdigo de la funcin generarClaveSHA1:

private string generarClaveSHA1(string nombre) { // Crear una clave SHA1 como la generada por // FormsAuthentication.HashPasswordForStoringInConfigFile // Adaptada del ejemplo de la ayuda en la descripcin de SHA1 (Clase) UTF8Encoding enc = new UTF8Encoding(); byte[] data = enc.GetBytes(nombre); byte[] result;

SHA1CryptoServiceProvider sha = 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 dgitos. StringBuilder sb = new StringBuilder(); for(int i= 0; i< result.Length; i++) { if( result[i] < 16 ) { sb.Append("0"); } sb.Append(result[i].ToString("x")); } // return sb.ToString().ToUpper(); }

Para que ese cdigo te funcione debes tener una importacin al espacio de nombres System.Security.Cryptography que es donde se define la clase SHA1CryptoServiceProvider y tambin 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 queras saber y que tantas veces me han preguntado... Un poco ms abajo tienes el cdigo 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. Tambin te dejo una utilidad para crear la base de datos de ejemplo y la tabla Usuarios con cuatro valores, dos de ellos usando texto normal y otros dos con las mismas claves, pero guardadas como una ristra de valores que corresponden con la cadena generada por la funcin generarClaveSHA1.

Nos vemos. Guillermo

Los ficheros con el cdigo


La utilidad para crear la base de datos y la tabla de usuarios de ejemplo: crearBaseEjemploClaves_SQL.rar 23.7 KB (MD5: F61A36A495989F0961C12700A21DEE75) El ejemplo completo para comprobar si el usuario y la clave son correctos: formLoginBaseDatos_cs.rar 15.7 KB (MD5: CB7DF77F3BC86C12C06F5504301C6E86)

Espacios de nombres usados en el cdigo de este artculo:


System.Windows.Forms System.Drawing System.Data.SqlClient System.Security.Cryptography System.Text

Acceder a una base de datos usando ADO y ADO.NET (desde una pgina .aspx)
En este artculo te muestro cmo usar los objetos de ADO y de ADO.NET para acceder a una base de datos de Access desde una pgina Web. As podrs comprobar cmo poder convertir tu cdigo anterior de Visual Basic 6.0 al que hay que usar con los lenguajes de .NET. Introduccin:
En realidad esto que te voy a mostrar es un ejemplo basado en algo que ya publiqu hace un par de aos, (concretamente en Enero de 2004), pero en esta ocasin te mostrar las dos formas de hacerlo poniendo el cdigo junto, con idea de que puedas ver las diferencias de acceder a una base de datos, (que en este caso ser de Access), usando los objetos de ADO: Recordset y Connection, adems de usar los "equivalentes" (o casi), de ADO.NET, en esta ocasin, usaremos tambin un objeto Connection y un DataTable, pero del espacio de nombres System.Data.OleDb, ya que el tipo de base a la que accederemos es de Access, aunque para acceder a una base de datos de SQL Server o cualquier otro tipo, pues... en fin, que tendrs que usar otros objetos de ADO.NET ms adecuados, etc., pero para mantener la cosa sencilla, no vamos a entrar en esas comparaciones. Lo mismo ocurre con el cdigo, solo mostrar el de Visual Basic, ya que de lo que se trata es de comparar el acceso con VBScript, (porque el acceso a datos lo haremos desde una pgina Web, de tipo .aspx), que como sabes es un "sucedneo" de Visual Basic 6.0, as que... no hay nada para C#, aunque si quieres ver un ejemplo parecido, puedes verlo en los ejemplos que publiqu en Enero de 2004, en el que si que mostraba los dos, el de Visual Basic y el de C#. Aqu tienes los links a esos dos ejemplos de hace un par de aos: Acceder a una base de datos de Access usando ADO, desde un formulario Web (.aspx)

Acceder a una base de datos de Access usando ADO.NET, desde un formulario Web

Una vez hechas las presentaciones, veamos cmo acceder a una base de datos de Access usando esas dos tecnologas. Como ya he comentado, el acceso lo haremos desde una pgina .ASPX, es decir,

desde una pgina de ASP.NET, s, aunque usemos ADO, se puede usar, pero de los pormenores, o detalles, de cmo hacer que se pueda usar ese sistema "obsoleto" de acceso a datos desde una pgina de ASP.NET, tendrs que verlo en el primero de los dos links que te he puesto antes, ya que aqu solo te mostrar qu cdigo usar para cada una de esas dos formas de acceder a los datos... incluso no pondr un ejemplo completo, que despus la gente se queja de que es muy complicado y se terminan perdiendo, as que... tendrs que echarle un poco de imaginacin y "pensar" un poco para que comprendas mejor todo... si no te enteras de nada, entonces significa que antes de entrar en esto deberas ver otras secciones tanto de cdigo ADO para Visual Basic 6.0 como de ADO.NET para Visual Basic .NET (incluido Visual Basic 2005).

Conectar a la base de datos y recuperar los datos


El cdigo "script" compatible con Visual Basic 6.0, usando ADO. Como sabes, en VBScript no se definen los tipos de datos, pero para que te hagas una idea, (por si quieres compararlo con una aplicacin normal de escritorio), la variable Rst sera de tipo ADODB.Recordset, y la variable Cnn sera del tipo ADODB.Connection.
' Variables usadas para crear los objetos, etc. Dim Rst, Cnn Dim sConn, sTip Dim sTitulo, sLink, sApartado, sDescripcion Dim sel, i

' Crear los objetos Cnn = Server.CreateObject("ADODB.Connection")

' Crear la conexin a la base de datos sConn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & _ Server.MapPath("datos\elguille.mdb") & ";" Cnn.Open(sConn) ' Crear la cadena SQL sel = "SELECT * FROM Titulos ORDER BY Apartado ASC" Rst = Cnn.Execute(sel)

El cdigo para Visual Basic .NET usando ADO.NET. En este cdigo no usamos ningn objeto del tipo Connection, ya que usamos un DataAdapter, y ese objeto solo necesita la cadena de conexin, pero no de una "conexin real".
Dim da As OleDbDataAdapter Dim dt As DataTable

Dim i, n As Integer Dim sel, sCnn As String ' sel = "SELECT * FROM Titulos ORDER BY Apartado ASC;" ' sCnn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & _ Server.MapPath("datos\elguille.mdb") & ";" ' Crear el DataAdapter da = New OleDbDataAdapter(sel, sCnn) ' ' Llenar el DataTable dt = New DataTable da.Fill(dt)

Como puedes comprobar, la cadena de conexin es la misma para los dos tipos de acceso a datos, la diferencia principal est en que el objeto Recordset de Visual Basic 6.0 lo creamos a partir del mtodo Execute de la conexin; mientras que en .NET la forma de recuperar los datos (una de ellas) es por medio del objeto OleDbDataAdapter, que es el que se encarga de recuperar los datos de la base de datos, y la forma de recuperarlos lo sabe por medio de la cadena de conexin. En ambos casos, los datos que se van a usar estn indicados por los datos de la cadena de seleccin (la variable sel). En el caso de ADO, esos datos los manipularemos por medio del Recordset, mientras que en ADO.NET vamos a usar un objeto DataTable. El primero lo "llenamos" usando el mencionado mtodo Execute, mientras que en el segundo, lo llenamos por medio del mtodo Fill del adaptador.

Navegar por los datos (mostrar todas las filas)


Una vez que ya tenemos los datos a los que queremos acceder, podremos navegar por ellos de la siguiente forma. En estos cdigos (primero el de ADO y despus del de ADO.NET), recorremos cada una de las filas que haya devuelto la cadena de seleccin usada (sel), los asignaremos a variables y los mostraremos, bueno, en realidad lo de mostrarlos es algo que no se hace en este cdigo, ya que es cosa tuya, porque lo que en realidad importa (al menos esa es mi intencin), es ver cdigo "compatible" entre ADO y ADO.NET. El cdigo de ADO que recorre todas las filas del Recordset:
' Buscar desde el principio Rst.MoveFirst i = 0 Do While Not (Rst.BOF Or Rst.EOF) i = i + 1 With Rst ' Asignar a las variables el contenido del registro

sTitulo = .Fields("Titulo").Value & "" sLink = .Fields("Link").Value & "" sApartado = .Fields("Apartado").Value & "" sDescripcion = .Fields("Descripcion").Value & ""

' Mostrar los datos de la fila actual ... Esto es cosa tuya ...

End With ' ' Mostrar el siguiente registro Rst.MoveNext Loop

If i = 0 Then ' No se ha encontrado ningn registro que coincida con la seleccin End If ' Rst.Close Cnn.Close

Rst = Nothing Cnn = Nothing

El cdigo de ADO.NET que recorre todas las filas de la tabla:


' n = dt.Rows.Count

If n = 0 Then ' No se ha encontrado ningn registro que coincida con la seleccin

Else

For i = 0 To n - 1 Dim sTitulo, sLink, sApartado, sDescripcion As String ' ' Asignar a las variables el contenido del registro sApartado = dt.Rows(i)("Apartado").ToString sTitulo = dt.Rows(i)("Titulo").ToString sLink = dt.Rows(i)("Link").ToString

sDescripcion = dt.Rows(i)("Descripcion").ToString

' Mostrar los datos de la fila actual ... Esto es cosa tuya ...

Next End If

Nota: En realidad, un cdigo "ms parecido" al de ADO, lo conseguiramos usando un objeto del tipo DataReader, el cual, a diferencia de la combinacin DataAdapter/DataTable, si que usa una conexin permanente a la base de datos, adems de que se obtiene por medio de un mtodo (ExecuteReader), en este caso, desde el objeto Command usado para realizar la seleccin indicada en la variable sel. Adems el DataReader tambin se utiliza para "navegar" de forma muy parecida al del Recordset... o casi... pero eso... lo mismo lo publico otro da, y por ahora, puedes practicarlo por tu cuenta, as de camino aprendes ms... (je, je... eso es lo que se dice cuando el que escribe no quiere hacer el ejemplo...) yo? que va! estoooo... es que... uf! cuantas cosas tengo que hacer!, adems... eso son cosas que dice del otro Guille... ;-)))

De cualquier forma, con o sin lo dicho en la nota, espero que todo esto te sea de utilidad. Nos vemos. Guillermo

Espacios de nombres usados en el cdigo de este artculo:


System.Data System.Data.OleDb

Acceder a una base de datos de Access usando ADO, desde un formulario Web (.aspx)
Publicado el 02/Ene/2004 Actualizado el 02/Ene/2004 Introduccin
En este ejemplo se accede a una base de datos de Access usando ADO. Como vers el cdigo ser parecido al que se usara en una pgina ASP normal. Lo nico que tenemos que hacer es: Indicar que se va a usar compatibilidad con COM. Esto se consigue indicando aspcompat = true en la directiva ASP.NET indicada al principio de la pgina. La forma de acceder a los objetos ADO (que son COM/ActiveX) ya que habr que usar cdigo "compatible" con punto NET, al menos en la forma de llamar a los mtodos y funciones, es decir usando los parntesis para encerrar los parmetros. Ya que por lo dems, el cdigo es "exactamente" el mismo que se usara con ASP y VBScript. Panorama

En el ejemplo siguiente, se da por supuesto que existe un directorio llamado "datos" que est en el mismo directorio que la pgina ASPX, si cambias la localizacin de ese directorio, tendrs que cambiar el cdigo de la conexin, ms concretamente en el parmetro a Server.MapPath(...). En el zip con el ejemplo, incluyo una pequea base de datos que es la usada en el formulario Web. Por tanto, si lo descomprimes, procura que la base de datos se quede dentro del

directorio "datos". De forma predeterminada se crear ese directorio. Dnde descomprimir el fichero? Dentro del directorio "localhost", por defecto es: C:\Inetpub\wwwroot Para acceder a la pgina de prueba, tendrs que usar http://localhost/ejemploAccessADO.aspx Por supuesto esto slo ser posible si tienes el Windows 2000/XP Profesional o un Windows Server que tenga instalado el IIS. En este ejemplo slo muestro el cdigo de Visual Basic, ya que al fin y al cabo es VBScript.

Nota: Este ejemplo realmente no utiliza ningn control ASP.NET, slo cdigo "puro y duro".

El link al cdigo de ejemplo: ejemploAccess.zip (13.4KB) El cual incluye tambin el ejemplo de acceso a ADO.NET (tanto para VB como para C#)

El cdigo para VBSCRIPT.

<% @Page aspcompat=true Language = VB %> <html> <head> <title>Acceso a datos con compatibilidad ASP (COM)</title> </head> <BODY bgcolor="#FFFFFF" text="#000000"> <p><font face="Verdana" size="4">Prueba de acceso a base de datos Access con ADO desde ASP.NET</font> <hr noshade size="3"> <font face="Verdana" size="2"> <br> <%

' Variables usadas para crear los objetos, etc. Dim Rst, Cnn Dim sConn, sTip Dim sTitulo, sLink, sApartado, sDescripcion Dim s, i ' Crear los objetos Cnn = Server.CreateObject("ADODB.Connection") ' Crear la conexin a la base de datos sConn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & _ Server.MapPath("datos\elguille.mdb") & ";" Cnn.Open(sConn) ' Crear la cadena SQL s = "SELECT * FROM Titulos ORDER BY Apartado ASC" Rst = Cnn.Execute(s) On Error Resume Next Err.Clear ' Buscar desde el principio Rst.MoveFirst i = 0 Do While Not (Rst.BOF Or Rst.EOF) i = i + 1 With Rst ' Asignar a las variables el contenido del registro sTitulo = .Fields("Titulo").Value & "" sLink = .Fields("Link").Value & "" sApartado = .Fields("Apartado").Value & "" sDescripcion = .Fields("Descripcion").Value & "" ' Mostrar los datos hallados Response.Write(i & "- <a href='" & sLink & "'>" & _ sTitulo & "</a> <b>(" & _ sApartado & ")</b><br>" & sDescripcion & "<br>") End With ' ' Mostrar el siguiente registro Rst.MoveNext Loop

Response.Write("<br>") Err.Clear If i = 0 Then Response.Write("<br><b>No se ha encontrado ningn registro que contenga") Response.Write(" lo que has especificado.</b><br>") Response.Write("Pulsa en este link para <b>") Response.Write("<a href='mostrarDatosTodo.aspx'>" Response.Write("Mostrar todos los registros</a></b>.<br>") End If ' Rst.Close Cnn.Close Rst = Nothing Cnn = Nothing ' %> <hr noshade size="3"> </font> </body> </html>

Acceder a una base de datos de Access usando ADO.NET, desde un formulario Web
Publicado el 02/Ene/2004 Actualizado el 02/Ene/2004 Introduccin
En este ejemplo se accede a una base de datos de Access usando ADO.NET. Como vers el cdigo es parecido al que se usara en una aplicacin normal, ya que no me cansar de repetir que en ASP.NET el lenguaje usado ser el mismo que en el resto de aplicaciones .NET, ya que no existe una versin especial para usar en pginas Web, cosa que si ocurra con ASP normal. En el ejemplo siguiente, se da por supuesto que existe un directorio llamado "datos" que est en el mismo directorio que la pgina ASPX, si cambias la localizacin de ese directorio, tendrs que cambiar el cdigo de la conexin, ms concretamente en el parmetro a Server.MapPath(...). En el zip con el ejemplo, incluyo una pequea base de datos que es la usada en el formulario Web. Por tanto, si lo descomprimes, procura que la base de datos se quede dentro del directorio "datos". De forma predeterminada se crear ese directorio. Dnde descomprimir el fichero? Dentro del directorio "localhost", por defecto es: C:\Inetpub\wwwroot Para acceder a la pgina de prueba, tendrs que usar http://localhost/ejemploAccessADONET.aspx Por supuesto esto slo ser posible si tienes el Windows 2000/XP Profesional o un Windows Server que tenga instalado el IIS. Panorama

Nota: Este ejemplo realmente no utiliza ningn control ASP.NET, slo cdigo "puro y duro".

El link al cdigo de ejemplo: ejemploAccess.zip (13.4KB) El cual incluye tambin el ejemplo de acceso a ADO

Notas sobre el cdigo ASP.NET (aunque poco) mostrado: Sobre la importacin de espacios de nombres en pginas ASP.NET: En el cdigo aqu usado se encuentra dentro de la misma pgina Web, esto es diferente a cuando se compila con Visual Studio .NET. Pero como esta ser la forma ms habitual de hacer pginas ASPX, (al menos cuando son simples como en este caso), por aquello de que no es necesario compilar el cdigo ni nada de eso, y por tanto podemos crearlas "al vuelo". Pues en estos casos, si necesitamos importar espacios de nombres, lo haremos usando cdigo ASP.NET, en este caso ser usando <%@Import Namespace = "..." %> Este cdigo es cdigo ASP.NET y por tanto vlido para cualquier lenguaje, es decir, no te confundas porque se use Import, que parece que sera el cdigo a usar en VB .NET, y pienses que para C# se usara using. Si eres observador, en Visual Basic realmente se usa Imports, con una "s" al final. La declaracin de los objetos a usar se hace de la misma forma que con el cdigo "normal", (recuerdas lo que dije al principio? en ASP.NET se usa el mismo lenguaje que en el resto de aplicaciones de .NET), lo nico que es diferente es que para hacer ciertas cosas en las pginas Web usaremos instrucciones (u objetos) propios para hacer ciertas cosas: Por ejemplo, para averiguar el path "real" de un directorio de nuestro sitio Web, usaremos Server.MapPath(), esto devolver una cadena con la localizacin real dentro del disco duro del servidor. Por otro lado, si queremos "escribir" algo en la pgina Web, usaremos Response.Write(). Lo que pongamos en el parmetro, ser lo que se muestre en la pgina como si lo hubisemos escrito dentro de la propia pgina HTML, por tanto el cdigo que escribamos debe tener formato HTML, por ejemplo, se usar <br> para indicar un cambio de lnea. Estos "objetos" se usan de la misma forma que en ASP clsico y son funciones vlidas tanto para Visual Basic .NET como para C#. Fjate tambin que cuando escribimos el cdigo dentro de Form_Load, ste se ejecuta desde arriba... es decir, es lo primero que se muestra en la

pgina. Una vez que se ha ejecutado el cdigo de Form_Load, se seguir con lo que hayamos escrito dentro del "cuerpo" de la pgina, es decir lo que est entre los tagas HTML <body> y </body>. Un detalle en cuanto al cdigo de Visual Basic .NET. Como sabrs, por defecto, VB no es estricto con la declaracin de variables ni con la conversin de datos. En este ejemplo, como no se le ha indicado lo contrario, se supone que la opcin "Option Strict" est desconectada. Por eso nos permite asignar a una variable de tipo String el contenido de un elemento de una fila, por ejemplo: dt.Rows(i).Item("Apartado"), si este mismo cdigo lo queremos escribir en una aplicacin normal de Windows usando Option Strict On, tendramos que usar este otro cdigo: dt.Rows(i).Item("Apartado").ToString, que es lo que al final hacemos en el cdigo de C#. Pongo aparte lo que hay que hacer, para que quede claro y resaltado... Ya sabes que a mi me gusta usar siempre la opcin estricta, aunque en este ejemplo lo he omitido para poder explicarlo. De todas formas, el cdigo incluido en el zip tiene esa opcin activada.

Si queremos activar Option Strict en una pgina ASP.NET tendremos que indicarlo en la directiva <%@ Page indicando Strict = true (o false si lo queremos desactivar), por ejemplo: <%@ Page Language = VB Strict = true %> Por qu ser tan estrictos? Porque as haremos las cosas "bien" y si hacemos algo mal: una asignacin o una declaracin, la haremos porque nosotros queremos hacerla, no porque "nos hayamos equivocado al hacerla". Por favor usa siempre Option Strict On en tu cdigo.

El cdigo para VB .NET

<% @Page Language = VB %> <%@Import Namespace="System.Data"%> <%@Import Namespace="System.Data.OleDb"%> <Script Language=VB Runat=Server> Sub Page_Load(sender As Object, e As EventArgs) Dim cnn As OleDbConnection Dim cmd As OleDbDataAdapter dim dt As DataTable dim i, n As Integer dim s As String ' Response.Write("<p><font face='Verdana' size='4'>") Response.Write("Prueba de acceso a base de datos Access con ADO.NET y ASP.NET") Response.Write("</font><hr noshade size='3'>") Response.Write("<p><font face='Verdana' size='2'> ") ' s = "SELECT * FROM Titulos ORDER BY Apartado ASC;" ' cnn = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" & _ Server.MapPath("datos\elguille.mdb") & ";") ' Crear el comando cmd = New OleDbDataAdapter(s, cnn) ' ' Llenar el DataTable dt = New DataTable cmd.Fill(dt) ' n = dt.Rows.Count If n = 0 then Response.Write("<p>No hay registros.</p>") Else Response.Write(n.ToString & " registros hallados.<br>") Response.Write("<p>") For i = 0 To n - 1 Dim sTitulo, sLink, sApartado, sDescripcion As String ' sApartado = dt.Rows(i).Item("Apartado")

sTitulo = dt.Rows(i).Item("Titulo") sLink = dt.Rows(i).Item("Link") sDescripcion = dt.Rows(i).Item("Descripcion") Response.Write((i + 1).ToString("0000") & _ "- <a href='" & sLink & "'>" & _ sTitulo & "</a><b>(" & _ sApartado & ")</b><br>" & sDescripcion & "<br>") Next Response.Write("</p>") End If Response.Write("</font></p>") End Sub </Script> <html> <head> <title>Acceso a datos usando ADO.NET</title> </head> <BODY bgcolor="#FFFFFF" text="#000000">

<hr noshade size="3"> </body> </html>

El cdigo para C# <% @Page Language = C# %> <%@Import Namespace="System.Data"%> <%@Import Namespace="System.Data.OleDb"%> <Script Language=C# Runat=Server> void Page_Load(object sender, EventArgs e){ OleDbConnection cnn; OleDbDataAdapter cmd;

DataTable dt; int i, n; string s; // Response.Write("<p><font face='Verdana' size='4'>") Response.Write("Prueba de acceso a base de datos Access con ADO.NET y ASP.NET"); Response.Write("</font><hr noshade size='3'>"); Response.Write("<p><font face='Verdana' size='2'> "); // s = "SELECT * FROM Titulos ORDER BY Apartado ASC;"; // cnn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + Server.MapPath(@"datos\elguille.mdb") + ";"); // Crear el comando cmd = new OleDbDataAdapter(s, cnn); // // Llenar el DataTable dt = new DataTable(); cmd.Fill(dt); // n = dt.Rows.Count; if( n == 0 ) Response.Write("<p>No hay registros.</p>"); else{ Response.Write(n.ToString() + " registros hallados.<br>"); Response.Write("<p>"); for(i = 0; i<n; i++){ string sTitulo, sLink, sApartado, sDescripcion; // sApartado = dt.Rows[i]["Apartado"].ToString(); sTitulo = dt.Rows[i]["Titulo"].ToString(); sLink = dt.Rows[i]["Link"].ToString(); sDescripcion = dt.Rows[i]["Descripcion"].ToString(); Response.Write((i + 1).ToString("0000") + "- <a href='" + sLink + "'>" + sTitulo + "</a><b>(" + sApartado + ")</b><br>" + sDescripcion + "<br>"); }

Response.Write("</p>"); } Response.Write("</font></p>"); } </Script> <html> <head> <title>Acceso a datos usando ADO.NET (cdigo de C#)</title> </head> <BODY bgcolor="#FFFFFF" text="#000000">

<hr noshade size="3"> </body> </html>

Вам также может понравиться