Ticker

6/recent/ticker-posts

ASP.NET Core 3.1 - LOGIN en MVC con C# y ADO.Net



Hola nuevamente, hoy quiero compartirles los pasos para el desarrollo e implementación del ya muy conocido Inicio de Sesión (LOGIN) haciendo uso de ASP.NET Core con el patrón de MVC haciendo uso del lenguaje de programación C#.

Además, haremos uso de la base de datos de Microsoft SQL Server 2017 para la creación del procedimiento almacenado (implementación - Transact-SQL); mencionar que hará uso de la tabla Usuario creado en el proyecto ASP.NET Core - Implementando CRUD en MVC con C#.


Requisitos:

  • Microsoft Visual Studio Community 2019
  • Microsoft .NET Core, ASP.NET Core 3.1
  • Microsoft SQL Server 2017 (RTM-GDR) - Express Edition (64-bit)
  • Framework Bootstrap (para mejorar el diseño de nuestra aplicación)
  • Framework  jQuery Validation (para la validación de lado del cliente)

Lo que veremos en este articulo:

Paso 1: Crear el procedimiento almacenado - Transact-SQL.
Paso 2: Implementar la cadena de conexión a la base de datos.
Paso 3: Agregar los paquetes de dependencia desde NuGet.
Paso 4: Implementar el método de validación.
Paso 5: Crear la entidad usuario y agregar atributos.
Paso 6: Modificar la Configuración del Startup.
Paso 7: Agregar el controlador e implementar los ActionResults.
Paso 8: Agregar e implementar la vista Login.cshtml.
Paso 9: Modificar la vista _Layout.cshtml.
Paso 10: Pantalla del demo desarrollado.


Ante de iniciar con el desarrollo del ya conocido Login (Inicio de Sesión), se debe crear el proyecto de nombre DEMO03_LOGIN, recomiendo revisar el articulo ASP.NET Core - CRUD en MVC con C# - Parte 1 donde se crear un proyecto desde cero de tipo ASP.Net Core, además detallamos la estructura del proyecto, configuración de la Aplicación y creación del Layout, ViewImports, ViewStart e importar la librería Bootstrap y sobre la edición de una página de Razor. Sin mayor detalles iniciemos con la implementación:


Paso 1: Crear el procedimiento almacenado - Transact-SQL.

Creamos el procedimiento almacenado GET_SEG_USUARIO haciendo referencia a la tabla Usuario de la base de datos BD_SEGURIDAD que se creo en el articulo ASP.NET Core - CRUD en MVC con C# - Parte 2; en primer instancias ingresamos a Microsoft SQL Server 2017 y clic en New Query o Nueva consulta para crear el procedimiento Almacenado:

CREATE PROCEDURE [dbo].[GET_SEG_USUARIO]

       @usuario VARCHAR    (50),

       @contrasena VARCHAR (250)

AS

BEGIN

    SELECT usuario, contrasena

    FROM   Usuario

       WHERE usuario = @usuario AND contrasena = @contrasena

END

El procedimiento almacenado cuenta con 2 parámetros (@us8uario y @contrasena) de entrada con el fin de retornar el usuario y contraseña de acuerdo a los datos ingresado desde la aplicación que se restringe desde el Script de Transact-SQL con la sentencia básica del Where (WHERE usuario = @usuario AND contrasena = @contrasena).


Paso 2: Implementar cadena de conexión a la base de datos.

La cadena de conexión se encarga de almacenar los parámetros para acceder a la base de datos desde la aplicación. Clic derecho en el nombre del proyecto en el Explorador de soluciones y seleccione Agregar, Nuevo elemento. Cuando se abra la ventana Agregar nuevo elemento, seleccione Archivo appsettings.json que se usa para configurar aplicaciones web, finalmente haga clic en el botón Agregar.
Clic en Agregar
En el archivo appsettings.js creado agregar la siguiente cadena de conexión: 

{

  "ConnectionStrings": {

    "DefaultConnection": "Data Source=HPAREDES\\SQLEXPRESS;Database=BD_SEGURIDAD;UID=usuario_para_acceder_al_server;Password=contraseña_para_acceder_al_server"

  }

}

Estos parámetros son el nombre del servidor y el nombre de la base de datos. Asimismo, contiene la información de seguridad, como el nombre de usuario y la contraseña para la conexión al servidor de base de datos. La cadena de conexión se almacena dentro del archivo appsettings.json que se crea en la raíz de la aplicación.

Paso 3: Agregar los paquetes de dependencia desde NuGet.

Clic en Herramientas/Administrador de paquetes NuGet/Administrar paquetes NuGet para la solución, seguidamente buscar e instalar los siguientes paquetes Microsoft.AspNetCore.Session y Microsoft.Data.SqlClient. Además, la instalación se puede realizar desde la consola NuGet haciendo uso del comando Install-Package:

Microsoft.AspNetCore.Session: Encargado de conservar los datos de usuario entre las peticiones realizadas.
Microsoft.Data.SqlClient: Controlador de acceso a datos, compatible con .NET Core y .NET Framework. 

Microsoft.Data.SqlClient es la creación de un nuevo SqlClient, es un nuevo espacio de nombre que permite la convivencia del antiguo System.Data.SqlClient.


Paso 4: Implementar el método de validación.

Implementaremos nuestro demo para poder validar los datos que serán ingresados desde nuestra vista login, datos como el usuario y la contraseña de la persona que intenta ingresar a la aplicación.

Iniciamos creando un directorio de nombre CustomValidation en la raíz del proyecto y agregamos una clase ContrasenaValidate e iniciamos el namespace ModelBinding Validation y accedemos a la interfaz IModelValidator que nos ofrece el mismo Framework Microsoft.AspNetCore.Mvc e implementamos la función de tipo de inyección de dependencias de nombre Validate:

using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;//Iniciamos el namespace ModelBinding Validation

namespace DEMO03_LOGIN.CustomValidation

{

    public class ContrasenaValidate : Attribute, IModelValidator//Acceder a la interfaz IModelValidator

    {

        public string ErrorMessage { get; set; }

        /// <summary>

        /// Función para la retornar validación - función con inyección de dependencia

        /// </summary>

        /// <param name="context"></param>

        /// <returns></returns>

        public IEnumerable<ModelValidationResult> Validate(ModelValidationContext context)

        {

                return new List<ModelValidationResult>

                {

                    new ModelValidationResult("", ErrorMessage)

                };

        }

    }

}


Paso 5: Crear la entidad usuario y agregar atributos.

Para esto debes crear un directorio de nombre Models en la raíz del proyecto, seguidamente clic derecho en el directorio creados y seleccione Agregar, Nuevo elemento; al abrir la ventana seleccione una nueva Clase y asigne el nombre de ClsUsuario. Agregue los siguientes atributos a esta clase:

    public class ClsUsuario

    {

        public int id { get; set; }  

        [Required]

        public string usuario { get; set; }

        [Required]

        [ContrasenaValidate(ErrorMessage = "Contraseña no valida")]

        public string contrasena { get; set; }

        public int intentos { get; set; }

        public decimal nivelSeg { get; set; }

        public DateTime? fechaReg { get; set; }

    }

Los atributos usuario y contrsena aplica el atributo RequiredAttribute, quiere decir que ambos atributos son obligatorio a ser ingresados; adicional se esta definiendo una validación personalizada haciendo referencia a la clase creada [ContrasenaValidate(ErrorMessage = "Contraseña no valida")] esto quiere decir que: El campo de datos del usuario y contraseña no puede estar vacío. Si la validación falla, el código genera una excepción de validación y muestra un mensaje de error. El mensaje de error se especifica en el momento en que se aplica el atributo al campo de datos.

Descripción de cada atributos:


Id: Campo para identificar el registro, atributos principal.
usuario: Registra la descripción del usuario.
contrasena: Registra la contraseña del usuario.
intentos: Cantidad de intentos de acceso del usuario.
nivelSeg: Nivel del seguridad de acceso.
fechaReg: Fecha de registro del usuario.


Paso 6: Modificar la Configuración del Startup.

Seguidamente ubicamos y abrimos el archivo Startup.cs, en el método de ConfigureServices de tipo void agregamos el services addSession. Asimismo, en el método Configure agregamos app.UseSession y modificación del template del router:

using Microsoft.AspNetCore.Builder;

using Microsoft.Extensions.DependencyInjection;

 

namespace DEMO03_LOGIN

{

    public class Startup

    {

        public void ConfigureServices(IServiceCollection services)

        {

            services.AddMvc(option => option.EnableEndpointRouting = false);

            services.AddSession();

        }

 

        public void Configure(IApplicationBuilder app)

        {

           app.UseSession();

            app.UseMvc(router =>

            {

                router.MapRoute(

                name: "default",

                template: "{controller=Login}/{action=Login}/{id?}");

            });

        }

    }

}


Paso 7: Agregar el controlador e implementar los ActionResults.

Cree el directorio Controllers en la raíz de la aplicación, en esta carpeta agregue un nuevo controlador (Controlador de MVC: en blanco) llamado LoginController.cs e inicializamos los namespace necesarios y crea los ActionResults.

Inicializamos los siguientes namespace (espacio de nombre) :

using System.Collections.Generic;//Lista de colecciones genericas

using System.Data;//Identificar el tipo de objeto a manipular en base de datos

using Microsoft.Data.SqlClient;//Controlador de acceso a datos

using System.Linq;//Para hacer macth entre lista del dataReader y los antributos del modelo (usuario y contrasena)

using DEMO03_LOGIN.Models;//Para instanciar los atributos de la entidad usuario

using Microsoft.Extensions.Configuration;//Para acceder al archivo de configuración appsettings.json

using Microsoft.AspNetCore.Http;//Para el manejo de solicitudes y respuestas HTTP

Seguidamente creamos una variable de tipo constante (para el valor de la sesión); además, creamos una interfaz para acceder al archivo de configuraciones que será través de la función Inyección de dependencias (acceder a la conexión a base de datos):

        /// <summary>

        /// Constante para Inicializar la Sesión _User

        /// </summary>

        const string SessionUser = "_User";

        public IConfiguration Configuration { get; }

        /// <summary>

        /// Interfaz para acceder a los valores del archivo de configuración

        /// </summary>

        /// <param name="configuration"></param>

        public LoginController(IConfiguration configuration)

        {

            Configuration = configuration;

        }

Finalmente creamos los siguiente ActionResults:

Login: Action para inicializar la carga de la vista del Login en base a los atributos de modelo usuario. Además, del Action de tipo POST para  para inicializar el proceso de validación e iniciar sesión en  base a los datos del modelo.

LogOff: Action de tipo POST para limpiar y cerrar la sesión de la aplicación

        /// <summary>

        /// Action para inicializar la carga de la vista del Login en base a los atributos de modelo usuario

        /// </summary>

        /// <returns></returns>

        public ActionResult Login()

        {  

            //ViewBag.ReturnUrl = returnUrl;

            return View(new ClsUsuario());

        }

 

        /// <summary>

        /// Action de tipo POST para  para inicializar el proceso de validación e iniciar sesión en  base a los datos del modelo

        /// </summary>

        /// <param name="model"></param>

        /// <returns></returns>

        [HttpPost]

        //[ValidateAntiForgeryToken]

        public ActionResult Login(ClsUsuario model)

        {  

            //Conexión a la base de datos

            string connectionString = Configuration["ConnectionStrings:DefaultConnection"];

            //Estoy usando uso de ADO.Net para interactuar con la base de datos

            using (SqlConnection connection = new SqlConnection(connectionString))

            {

                var list_users = new List<ClsUsuario>();

                //@1Inicio: Validar los controladores

                if (model.usuario == null || model.usuario.Equals("") ||

                    model.contrasena == null || model.contrasena.Equals(""))

                {

                    ModelState.AddModelError("", "Ingresar los datos solictiados");

                }//@1Final

                else

                {

                    connection.Open();//Abrir la conexión a la base de datos

                    SqlCommand com = new SqlCommand("GET_SEG_USUARIO", connection);//Referencia al procedimiento almacenado

                    com.CommandType = CommandType.StoredProcedure;//Se define el tipo de comando a utilizar

                    //Paso los parámetros de acuerdo a los datos cargados segun el modelo usario

                    com.Parameters.AddWithValue("@usuario", model.usuario);

                    com.Parameters.AddWithValue("@contrasena", model.contrasena);

                    SqlDataReader dr = com.ExecuteReader();//Ejecuto el comando a través de un DataReader

                    //@2Inicio: Recorro los datos y adiciono en la lista list_users los valores usuario y contrasena

                    while (dr.Read())

                    {

                        ClsUsuario clsUsuario = new ClsUsuario();

                        clsUsuario.usuario = Convert.ToString(dr["Usuario"]);

                        clsUsuario.contrasena = Convert.ToString(dr["Contrasena"]);

 

                        list_users.Add(clsUsuario);//Adicionar en la lista

                    }

                    //@2Final

 

                    //@3Inicio: Match entre los valores ingresados y la lista

                    if (list_users.Any(p => p.usuario == model.usuario && p.contrasena == model.contrasena))

                    {

                        HttpContext.Session.SetString(SessionUser, model.usuario);//Iniciamos la sesión pasando el valor (nombre del usuario)

                       

                        return RedirectToAction("Usuario", "Home");//Redireccionar a la vista usario (Lista de Usuarios)

                    }

                    else

                    {

                        ModelState.AddModelError("", "Datos ingresado no válido.");//Error personalizado

                    }

                }

                return View(model);

            }

        }

 

        /// <summary>

        /// Action para limpiar y cerrar la sesión de la aplicación

        /// </summary>

        /// <returns></returns>

        [HttpPost]

        //[ValidateAntiForgeryToken]

        public ActionResult LogOff()

        {

            HttpContext.Session.Clear();//Limpiar la sesión

            return RedirectToAction("Login", "Login");//Redireccionar a la vista login

        }


Paso 8: Agregar la vista Login e implementar el cshtml.

Para desarrollar la vista, ubícate en el code behind del Action Login "public ActionResult Login()" (que esta en el controlador LoginController.cs ) clic derecho y cli en agregar vista, seguidamente seleccionar la plantilla en Empty(sin modelo) y desmarque las opciones crear como vista parcial  y usar página de diseño, ahora en el HTML agregamos las siguientes instrucciones:

@@1 Inicio: Importamos el modelo usuario y definimos un titulo. 
@@2 Inicio: Importamos la librería js jQuery, el css bootstrap y asimismo posicionamos el formulario. 
@@3 Inicio: Formulario con método de tipo post para validar o iniciar el acceso a la aplicación.

<!--@@1 Inicio: Importamos el modelo usuario y definimos un titulo-->

@model DEMO03_LOGIN.Models.ClsUsuario

@{

    var title = "Acceso al Sistema";

    ViewData["Title"] = title;

    Layout = null;

}

<!--@@1 Final-->

 

<!DOCTYPE html>

<html>

<head>

    <meta name="viewport" content="width=device-width" />

    <title>@title</title>

    <!--@@2 Inicio: Importamos la librería js jQuery, el css bootstrap y asimismo posicionamos el formulario-->

    <link href="/lib/bootstrap-4.3.1/dist/css/bootstrap.css" rel="stylesheet" />

    <script src="/lib/jquery/dist/jquery.min.js"></script>

 

    <style><

        .form-signin {

            margin: 0 auto;

            max-width: 330px;

            padding: 15px;

        }

 

            .form-signin h4 {

                text-align: center;

            }

    </style>

    <!--@@2 Final-->

</head>

    <body>

 

    <div class="container">

        <div class="row justify-content-center">

            <h3>LOGIN MVC ASP.Net Core 3.1</h3><!--Definimos una cabecera en la página-->

        </div>

    </div>

    <div class="container body-content">

        <!--@@3 Inicio: Método de tipo post para validar o iniciar el acceso a la aplicación-->

        @using (Html.BeginForm("Login", "Login", FormMethod.Post, new { @class = "form-signin", role = "form" }))

            {

                @Html.AntiForgeryToken()

                <h4>@title</h4>

 

                @Html.ValidationSummary(true, "", new { @class = "text-danger" })

 

                @Html.TextBoxFor(m => m.usuario, new { @class = "form-control", placeholder = "Usuario" })

                @Html.ValidationMessageFor(m => m.usuario, "", new { @class = "text-danger" })

                <br />

                @Html.PasswordFor(m => m.contrasena, new { @class = "form-control", placeholder = "Contraseña" })

                @Html.ValidationMessageFor(m => m.contrasena, "", new { @class = "text-danger" })

                <br />8

                <input type="submit" value="Iniciar sesión" class="btn btn-lg btn-primary btn-block" />

            }

        <!--@@3 Final-->

        </div>

    </body>

</html>


Paso 9: Modificar la vista _Layout.cshtml.

Ahora agregaremos la opción de cerrar sesión y mostraremos el nombre del usuario que inicia la sesión en la aplicación, todo esto se implementará en la vista _Layout.cshtml que fue creado en el articulo de la implementación del CURD. Para lograr todo esto se agregarán las siguientes instrucciones:

@@1 Inicio: Importamos el name para la comnicación http y capturamos el valor de sesión.
@@2 Inicio: Importamos la librería js jQuery y el css bootstrap.
@@3 Inicio: Pasar el valor de la variable vUser (sessión) a al parráfo; además invocamos al Action LogOff para cerrar la sesión.

<!--@@1 Inicio: Importamos el name para la comnicación http y capturamos el valor de sesión-->

@using Microsoft.AspNetCore.Http

@{

    var vUser = Context.Session.GetString("_User");<!--Capturar la sesión en la variable vUser-->

}

<!--@@1 Final-->

<!DOCTYPE html>

<html>

<head>

    <meta name="viewport" content="width=device-width" />

    <title>@ViewData["Title"]</title><!--Capturamos el titulo definido en el vista que corresponda (en este caso sera de la vista Index - LISTAR USUARIO)-->

    <!--@@2 Inicio: Importamos la librería js jQuery y el css bootstrap-->

    <link href="/lib/bootstrap-4.3.1/dist/css/bootstrap.css" rel="stylesheet" />

    <script src="/lib/jquery/dist/jquery.min.js"></script>

    <!--@@2 Final-->

</head>

<body>

    <div class="container">

 

        <div class="row justify-content-lg-center">

            <div class="row">

                <div class="col-12 badge-info">

                    <h3>LOGIN MVC ASP.Net Core 3.1</h3><!--Cabera de la página-->

                </div>

            </div>

        </div>

 

        <div class="row justify-content-lg-end">

            <div class="row">

                <!--@@3 Inicio: Pasar el valor de la variable vUser (sessión) a al parráfo; además invocamos al Action LogOff para cerrar la sesión-->

                <div class="col">

                    <p>USUARIO: @vUser</p><!--valor de la sesión-->

                </div>

                <div class="col">

 

                    @using (Html.BeginForm("LogOff", "Login", FormMethod.Post, new { id = "logoutForm", @class = "form-css" }))

                    {

                        <a href="javascript:document.getElementById('logoutForm').submit()"><i class="fa fa-fw fa-power-off"></i> Cerrar Sesión</a>

                    }

                </div>

                <!--@@3 Final-->

            </div>

        </div>

    </div>

 

    <div class="container body-content">

        @RenderBody()

        <hr />

        <footer class="row justify-content-center">

            <p>

                © 2017 - @DateTime.Now.Year

                <a href="http://www.hadsonpar.com/" target="_blank">HadsonPar</a> |

                My LOGIN Application MVC ASP.Net Core 3.1

            </p>

        </footer>

    </div>

</body>

</html>


Paso 10: Pantalla del demo desarrollado.

En cada pantalla describiremos la funcionalidad o acción que esta realizando la aplicación:
La primera validación es retornada desde el ActionLogin, las 2 siguientes son gracias a los atributos que esta definidos como Required (mayor detalle en el paso 5), recuerda que puedes personalizar lo mensajes. 

El segundo mensaje de "Contraseña no valida" es un tipo de mensaje personalizado haciendo uso de un función de inyección de dependencia (mayor detalle en el paso4). 

Ingresar los datos correctos y acceder a la aplicación.

En la vista index se muestra la lista de Usuario y la opción Cerrar Sesión se encuentra en la vista compartido _Layout.cshtml
.


Fuente disponible

Gracias nuevamente 😊; comentarios y apreciaciones son bienvenido, un fuerte abrazo para todos ✌...!!!

Publicar un comentario

4 Comentarios

  1. Gracias por el excelente artículo en .NET core, si alguien quiere consultarlo en .NET MVC revise aquí

    Login and register in ASP.NET MVC

    ResponderBorrar
    Respuestas
    1. Hola Miguel, gracias por el comentarios y aporte. Saludos.

      Borrar
  2. Buenas noches, encontré un error logico en el proyecto, se puede pasar directamente al index si pasar por el login, y poder ver el listado completo de los usuarios ya registrados, saludos.

    ResponderBorrar
    Respuestas
    1. Hola, gracias por el comentario - déjame revisar el demo y te comento como me va. Saludos.

      Borrar