En este post vamos a tratar de aplicar seguridad en nuestra aplicación web. Y cómo la seguridad en aplicaciones web es un tema tan grande vamos a tratar en concreto con la protección de ciertas partes de la web, y con ella su funcionamiento, a ciertos usuarios. 

Para ello vamos a establecer primero un sistema para loguear a los usuarios, dándoles dos tipos de rol diferentes (usuario básico y admin). En función del rol que les otorguemos van a poder recibir un tipo de privilegios u otro.  

Aunque este tipo de seguridad de puede aplicar a cualquier tipo de aplicación web, vamos a usar una aplicación MVC 5. El proyecto está subido en mi repositorio GIT . En él vamos a simular el funcionamiento de una gasolinera en la que tenemos 3 tipos de privilegios. El más bajo, corresponde a todo usuario sin loguear, sólo puede ver el precio del combustible, los usuarios logueados  pueden además comprar gasolina, y los usuarios logueados que tengan el rol de administradores van a poder además cambiar los precios. 

Para comenzar desde Visual Studio vamos a crear un proyecto MVC vacío. 

Captura1

 

En el proyecto vamos a tener dos controladores. Se podría tener todo en uno mismo, pero de esta manera tenemos el código mejor estructurado. Vamos a comenzar por el controlador que va a llevar la lógica de la autentificación de los usuarios y lo vamos a llamar  ControlSeguridadController. 

En este controlador vamos a tener 3 métodos ActionResult, para el Login uno GET y otro POST y un tercer método que nos va a servir para cerrar la sesión. Vamos a comenzar con el método GET del Login.  

Captura2

 

Como podemos ver en la foto siguiente el método Login  no contiene más que un return de la vistaa la que hemos añadido algo de diseño aplicando una plantilla para que tenga un mejro aspecto, pero lo único importante de aquí es un formulario tipo post que va a enviar el valor de dos inputs, uno el usuario y otro la contraseña 

 

Captura3

Los String usuario y passw van a llegar al método POST de Loguin. Para este ejemplo vamos a usar String estáticos para validar a los usuarios. Esto lo vamos a hacer así para simplificar este post, pero lo correcto es ir a una base de datos para comprobar si la combinación usuario<=>contraseña es válida.  

En este ejemplo vamos a tener dos usuarios: usuario con contraseña usuario y admin con contraseña admin.  Si el usuario es admin vamos a redireccionarlo a la zona de administradores y si es un usuario normal a la zona de compras. Pero no olvidemos que los usuarios podrán navegar libremente por toda la app mientras tengas privilegios para hacerlo. 

 

Captura4

 

Y ya podemos comenzar con el proceso de Login propiamente dicho. Para ellos el proceso se divide en tres partes. La primera se realiza en el controlador tras validar que el usuario<=>contraseña es correcto.  

1º- Creamos un ticket. Vamos a usar el constructor de seis parámetros, pero no es el único que existe. En este constructor tenemos, por orden:  versión de la cookie, nombre del usuario, una marca de tiempo de cuando se ha creado el ticket, una marca de tiempo de cuando quieres caducar el log, un true o un false si quieres que sea persistente, y por último un object genérico. En este object, aunque se puede meter cualquier tipo de objeto, lo normal es meter el rol del usuario que se ha logueado. De esta forma vas a poder establecer diferentes códigos accediendo al rol del usuario que se ha logueado. 

2º- Encriptar el ticket. Tras la creación del ticket, hacemos uso del algoritmo de encrypt que viene en la librería FormsAuthentication. Esto se hace porque el ticket vamos a guardarlo en el cliente.  Por ello encriptamos los datos para que no se expongan y puedan ser utilizados con fines maliciosos.  

3º- Creamos cookie. La creación de la cookie la hacemos con constructor de dos parámetros de HttpCoockie. Los parámetros que usamos son por un lado el nombre que le vamos a dar a la cookie y por otro el cifrado del ticket que hemos hecho en el paso anterior.  

4- Añadimos la Coockie al cliente. Con Response.Cookies guardamos la cookie creada en el punto anterior para guardarla en el navegador del cliente.  

Cómo vemos en la foto siguiente el código es el mismo tanto para un admin como para un usuario normal, y en el último parámetro, en el rol, introduzco el nombre del usuario. El nombre de usuario lo vamos a usar como rol, recordamos que va a ser o «usuario» o «admin».

 

Captura5

 

Para terminar con el ControlSeguridadController vamos a crear un método ActionResult para cerrar sesión. En este método, por orden, vamos a: 

1- Eliminar al usuario de la App. Para ello hacemos uso de GenericPrincipal que es un tipo básico de usuario logueado. Para ello damos a la variable User un nuevo tipo de usuario que es un null de GenericPrincipal. 

2-Salir del modo autentificación. Hacemos uso de SignOut de la librería FormsAuthentication. 

3-Recuperamos la Cookie llamada TickerUsuario que el usuario tiene guardada en su navegador. 

4-Caducamos esa cookie 

5-Volvemos añadir la cookie al navegador del usuario para que sobrescriba la anterior que tenía. 

 

Captura6

 

Una vez terminado el trabajo en el controlador nos vamos Global.asax.cs. Aquí creamos el método Application_PostAuthenticateRequest(). Este método lo que hace es comprobar a nivel de servidor que el usuario que está realizando las peticiones está correctamente autentificado.  Voy a explicar por pasos el código: 

1-Recuperamos la cookie llamada TicketUsuario del cliente que hemos creado en el Login.  

2-En el caso de que esa cookie exista. 

3-Recuperamos los datos que hay almacenados en la cookie. 

4- Cómo los datos están encriptados los vamos a desencriptar usando la misma librería. Así podemos recuperar el ticket. 

5- Recuperamos el rol del usuario que viene en el ticket. 

6-Recuperamos el nombre del usuario. 

7- Creamos un GenericIdentity. Esta identidad almacena el nombre del usuario y nos va a servir para el siguiente paso. 

8- Con el GenericIdentity del paso anterior ya podemos crear el GenericPrincipal, que recordamos que es un tipo de usuario básico.  

 9- Una vez creado el usuario GenericPrincipal lo añadimos al contexto de la aplicación 

 

 

Captura7

 

 

Ya tenemos todo el sistema de autentificación montado en nuestra aplicación. Ahora lo único que nos queda es establecer que rol aceptamos para que métodos ActionResult. Para ello vamos a crear una clase que vamos a llamar NOMBREATTRIBUTE. Esto es así porque luego vamos a llamarle con [NOMBRE] delante de los métodos que vamos a proteger. 

Esta clase en mi proyecto de ejemplo lo voy a llamar SeguridadWebGasolinerasAttribute. Como vemos en la imagen esta clase hereda de AuthorizeAttribute. Gracias a ello vamos a poder por un lado a sobrescribir el método OnAuthorization y por otro vamos a crear un método  RedirectToRouteResult  para poder redirigir a los usuarios que intentan acceder a sitios prohibidos. 

 

Captura8

Vamos a comenzar con el método OnAuthorization, que recibe un objeto AuthorizationContext como parámetro. Vamos a explicar el código línea por línea. 

1-Heredamos de AuthorizeAttribute para implementar su funcionalidad. 

2-Confirmamos que el usuario está logueado. En caso de que no esté logueado vamos a redireccionar al Login de ControlSeguridadController. 

3-En caso de que esté logueado vamos a recuperar su GenericPrincipal desde el contexto de la aplicación. 

4- Preguntamos si la propiedad Role tiene valores. Esta propiedad viene implementada en la clase y permite pasarle objetos a la clase. Es muy útil en aplicaciones que tienen más de dos roles, como usuario, admin y super_admin ya que la hace reutilizable. Así cuando llamemos a nuestra clase vamos a poder enviarle una lista de  de roles en forma de String separados por comas [SeguridadWebGasolinera(Roles=”rol1,rol2,rol3”)] 

5-Inicializamos un contador que vamos a usar para saber cuántas vueltas ha dado el bucle. 

6-Creamos un Array de String partiendo la cadena Roles buscando una coma. De esa manera vamos a poder tener los roles admitidos de forma independiente. 

7- Vamos a recorrer el array que hemos creado en el paso anterior.  

8-En caso de que el usuario logueado tenga el rol permitido se rompe el bucle, por lo que le permitimos pasar. 

9- Sumamos el contador en cada iteración del bucle. 

10-En el caso que se haya terminado el bucle sí ha dado el mismo número de vueltas que posiciones tiene el Array de roles significa que el usuario no tiene un rol admitido para la zona a la que quiere acceder. 

 

Captura9

 

En el caso de que el usuario no esté logueado lo mandamos al login, y en el caso de que esté logueado pero no tenga permitido el acceso lo enviamos a una vista que tiene un mensaje de que no puede acceder. Para ello hacemos una llamada al método GetRuta pasándole como parámetros el controller/action donde vamos a redirigir .

 

Captura10

Ya tenemos todo el sistema de seguridad. Sólo tenemos que acoplar el atributo allí donde queremos permitir el acceso solo a ciertos usuarios. Para ello creamos un controlador que vamos a llamar controller. En este controlador solo tenemos 4 métodos GET para hacer las comprobaciones de que nuestro sistema funciona. 

Captura11

 

Tal y como vemos en la imagen anterior tan solo acoplamos con decoraciones y el nombre de nuestra clase attribute de seguridad, añadiendo como parámetro que roles son los permitidos:[SeguridadWebGasolineras(Roles = «admin,usuario»)]. 

Usando Razor hemos cambiado el diseño de nuestro Layout para añadir enlaces a las diferentes vistas y un menú de usuario para saber quién está logueado y que pueda cerrar sesión.  Se recomienda descargar el proyecto para poder ver mejor el layout.

 

Captura12

Y ya tenemos nuestra web protegida mediante el uso de autentificación de usuarios. El resultado en función del usuario logueado en cada momento se expone a continuación.

 

CapturaAdmin
Zona de usuarios administradores
CapturaUsuario
Zona de usuarios logueados

 

CapturaLogOut
Zona de usuarios sin loguear

Autor: Eduardo Bermúdez Blanco

 

Curso: Microsoft MCSA Web Applications + Microsoft MCSD App Builder + Xamarin

Centro: Tajamar

Año académico: 2018-2019

Repositorio en GIT HUB

Linkedin

Leave a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.