¿Como Crear Seguridad Personalizada en MVC?
Seguridad Personalizada
La capa de seguridad de MVC es una capa independientemente de las demás capas de un Proyecto de un MVC
Podemos añadir o quitar el capa de seguridad en cualquier momento de la creación del proyecto sin afectar a la funcionalidad del proyecto.
Lo que sirve la capa de seguridad es limitar el permiso de acceso a cierta página del proyecto por diferente role.
SOLUCIÓN RÁPIDA (copia código y Ya está)Preparación
la capa de seguridad se implementa sobre un proyecto de MVC funcional.
Así que, para la mostración de la implementación de la capa de seguridad, creamos un proyecto de ASP.NET con plantilla de MVC.
Que contiene dos Controlador: Empleado y Home . En el controlador de empleado contiene un método de GETLISTAEMPLEADO para obtener el listo del empleado (como este proyecto lo utilizamos para la demostración de capa de seguridad, utilizamos este método como un repositorio de un BBDD para facilitar la fase de creación del proyecto). Tambien tenemos un ACTION que devuelve una Vista llamado LISTAEMPLEADO que muestra el listado de los empledos. El controlador de Home Solo contiene un ACTION del Vista Index que muestra un LINK que dirige al Vista del LISTAEMPLEADO del controlador EMPLEADO.Si hacemos click sobre ese link nos lleva directamente al vista de la lista de empleado sin ningun problema.
Ejemplo de implementar la capa de seguridad
Lo que vamos a hacer es limitar el permiso de acceso al Vista de LISTADOEMPLEADO, solo el usuario que esta iniciado sesion y tiene el permiso de ADMIN puede entrarPaso que necesitamos hacer
- 1º paso crear controlador manage
- 2º paso configurar el fichero global.asax
- 3º paso crear AutorizarAttribute
- 4º paso implementar el AutorizarAttribute en el controlador o vista que quiere limitar el permiso de acceso
- 5º paso crea vista parcial para cerrar sesión
1º PASO crear controlador Manage
Creamos un controlador de manage(el nombre de controlar puede ser persalizado) lo utilizamos para manejar el login del usuario.
En el controlar creamos 4 ACTION que vamos a necesitar:- GET: LOGIN (mostrar la vista de login para iniciar sesion)
- POST:LOGIN(realizar autenticacion de cuenta y redirecionar al pagina del lista empleado)
- GET: ERRORACCESO(que se devuelve una vista que muestra el mensaje de que no tienes permiso de acceso de la pagina)
- GET: CERRARSESION(es una ACTION que utiliza para cerrar cession del usuario)
GET:Login (mostrar la vista de login para iniciar sesion) .
En la vista del login contiene un formulario para enviar los datos del usuario y password de formato POST.
POST:Login(realizar autenticacion de cuenta y redireccionar al pagina del lista empleado).
En el posta del Login recibimos el nombre de usuario y password Primero realizamos la comprobacion de que si existe el usuario o no .
Para facilizar el proceso de comprobacion aquí utilizamos un “IF” y solo con la cuenta del admin y del empleado, pero lo mas completo de realizar una comprobacion es conectar el proyecto con un BBDD y hacer la comprobacion con la tabla User.
Si el usuario y password que hemos recibido conincite con el admin o empleado añadimos el role y idempleado que pertenece a variable “role” y “idempleado” .
Después de la comprobación, si existe el usuario crea un TICK para almacenar los datos necesarios para crear una cookie.
Un TICK necesita siguientes datos.
- Numero de versión (de ejemplo ponemos 1)
- Nombre de identidad
- Fecha y hora de inicio
- Fecha y hora de expirar (indicar cuanto tiempo va a durar este TICK, puede ser minutos, horas o días)
- Persistente
- Un dato de tipo STRING que deseamos guardar para que podemos recuperar luego (en nuestro ejemplo guardamos el “role” del usuario)
Despues lo ciframos el TICK y lo guardamos en un COOKIE llamado “Usuario”.
Y despues hacemos un redireccion a la pagina de ListaEmpado del controlador Empleado.
En caso de no ha pasado la comprobacion lo enviamos de vuelta a la pagina de LOGIN para que vuelva ha introducir el Usuario y la contraseña.El cookie que hemos creado lo utilizamos luego en la Golbal.asax para crear la sesion.
GET: ErrorAcceso(devulve una Vista que se muestra el mensaje de que no tienes permiso de acceso de la pagina).
GET: CerrarSesion(se utiliza para cerrar cesion del usuario y redirecciona al pagina index del Home).
2º PASO Configurar Global.asax
Lo que hacemos en goblal.asax es meter el cookie del “Usuario” que hemos creado en el HTTPCONTEXT.CURRENT.USER. Dentro de Globax.Asax creamos un método con nombre de APPLICATION_POSTAUTHENTICATEREQUEST (ES METODO QUE SE EJECUTA EN EL SERVIDOR CON CADA INTENTO DE VALIDACION DE USUARIO).Vamos a necesitar utilizar la siguiente libreria.
lo que hacemos primero es una comprobación si existe el COOKIE del “Usuario” o no . sí existe, desciframos el COOKIE y usamos los datos de la cookie para crear un objeto GENERICPRINCIPAL y lo guardamos en el HTTPCONTEXT.CURRENT.USER.3º PASO crear AutorizarATTRIBUTE
Es una clase que esta heredada del AUTHORIZEATTRIBUTE .El nombre de” Autorizar” es personalizable, pero es obligatorio que termina con “Attribute”.
Esta clase lo utilizamos para comprobar si el usuario esta autentificado o no y también podemos limitar el permiso de acceso de cierta pagina.
Por ejemplo, ahora vamos a limitar que, solo el usuario que tiene role de ADMIN puede entrar en la página de LISTAEMPLEADO.Librería que necesitamos.
La clase debe estar heredado del AuthorizeAttribute. Creamos una sustitución del método OnAuthorization para realizar el autenticado del usuario. Con el primer “if” comprobamos si el usuario esta autenticado o no. Si está autenticado capturamos su role desde HttpContext.Current.User Si tiene el role de ADMIN lo dejamos entrar en la página de la LISTAEMPLEADO si no lo enviamos a la página de ERRORACCESO. Si no está autenticado le redireccionamos a la vista de LOGIN para que realiza la autenticación.4º paso implemetar el el Attribute Autorizar en el controlador o vista que quiere limitar el permiso de acceso
primero hacemos el using del carperta Attribute.
Para implementar la autenticación solo tenemos que añadir el [Autorizar] por encima del ACTION o CONTROLADOR que deseamos implementar la autenticación.
[Autorizar](es el nombre de clase de autenticación que hemos creamos) por defecto se omite el Attribute. Por ejemplo, lo añadimos al ACTION del LISTAEMPLEADO () del controlador EMPLADO.5º paso crea vista parcial de cerrar sesion
Tenemos que crear una Vista Parcial en el menú de navegación para que podemos cerrar sesión después iniciar sesión.
El menú de navegación suele estar en el LAYAOUT así que para crear la vista parcial en la carpeta SHARED para que podamos llamar desde LAYOAUT.Usamos un “if” para que solo se muestre esta vista parcial cuanto el usuario esta autenticado.
Y contiene una LINK que llama el método que hemos creado ante en el controlador de manager que sirve para cerrar sesión.
En LAYOUT utilizamos el HTML.PARCIAL para añadir la vista parcial de cerrar sesión.COMPROBACION
Ejecutamos el Proyecto, hacemos clic sobre el LINK del LISTAEMPLEDO Y no entrar directamente como antes, si no, nos redirecciona a la página de LOGIN Primero probamos iniciar sesión con la cuenta de ADMINDespués de iniciar sesión nos a dejado entrar en la página de lista empleado y también nos muestra la opción de cerrar sesión.
Ahora cerramos sesión y iniciamos de nuevo con la cuenta de Empleado.
Podemos ver que no tenemos permiso de acceder a la página del listado empleado .
Posible Problema
Con la configuración que hemos hecho anteriormente, hay un problema sobre el POST de LOGIN. Después de iniciar sesión siempre va a redireccionar a la página de LISTAEMPLADO. Por ejemplo, si creamos un nuevo ACTION llamado DETALLEEMPLEADO en el controlador EMPLEADO y añadimos la Autenticación. Añadimos un nuevo link en la página INDEX de HOME.Cuando hacemos clic sobre link de “Perfil” nos pide que iniciemos la sesión.
Pero después de iniciar sesión siempre nos lleva a la página de LISTAEMPLEADO y no a la página de detalles que hemos querido. Eso es por lo que he mencionado antes en la ACTION de POST de LOGIN tenemos un REDIRECTTOACTION con una dirección estática por eso siempre nos va a llevar siempre a la página de LISTAEMPELADO después de iniciar sesión. Tenemos que cambiar el REDICTTOACTION de la dirección estática a dinámica Para solucionar este problema tenemos que modificar la clase AUTORIZARATTRIBUTE y el ACTION POST de LOGINEn la clase de AUTORIZARATTRIBUTE
Primero capturamos el ACTION y CONTROLADOR que el usuario desea ir (capturar el usuario en que LINK ha hecho click) utilizando el ROUTEDATA.VALUE. Como cuando hacemos click sobre el LINK, es la primera vez que entramos en la AUTORIZARATTRIBUTE no va a estar autenticado así que guardamos el ACTION y el CONTROLADOR que hemos capturado en TEMPDATA para poder recuperarlo luego en POST de LOGIN.En el POST DE LOGIN (controlador de MANAGE)
En el POST de LOGIN recupera el ACTION y CONTROLADOR que hemos guardado y redireccionamos dinámicamente a la página que el usuario deseado ir (en la siguiente imagen hay un “if” porque el ACTION de DETALLAEMPLADO necesita recibir un IDEMPLEADO)Comprobación:
Solución Rápido (Sin preguntar porque COPIA y PEGALO siguiente código a tu PROYECTO DE MVC):
VolverCrear un Controlador llamado Manage
Las librerías que necesita para el ManageController
using System.Web.Mvc;
using System.Web.Security;
Y copia siguiente código y pégalo dentro del ManageController
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(string usuario, string password)
{
string role = null;
int idempelado=0;
//esta parte puede cambiarlo por un metodo que comprueba si el usuario y password que recipido coincide con tu BBDD o no
if (usuario.ToUpper() =="ADMIN" && password.ToUpper()=="ADMIN")
{
role = "ADMIN";
idempelado = 4;
}
else if (usuario.ToUpper() == "EMPLEADO" && password.ToUpper() == "EMPLEADO")
{
role = "EMPLEADO";
idempelado = 1;
}
if (role != null)
{
FormsAuthenticationTicket ticket =
new FormsAuthenticationTicket
(
1,
idempelado.ToString(),//este el valor que vamos a guarda en HttpContext.Current.User.Identity.Name
DateTime.Now,
DateTime.Now.AddMinutes(10),
true,
role //este es variable que guarda el valor de role
);
string datos = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie("Usuario", datos);
Response.Cookies.Add(cookie);
string action = TempData["action"].ToString();
string controlador = TempData["controlador"].ToString();
if (action== "DetalleEmpelado")
{
return RedirectToAction(action, controlador, new { idEmp = idempelado });
}
else
{
return RedirectToAction(action, controlador);
}
}
else
{
ViewBag.mensaje = "Usuario/Password incorrecto";
return View();
}
}
public ActionResult ErrorAcceso()
{
return View();
}
public ActionResult CerrarSesion()
{
HttpContext.User = null;
FormsAuthentication.SignOut();
HttpCookie cookie = Request.Cookies["Usuario"];
cookie.Expires = DateTime.Now.AddMinutes(-30);
Response.Cookies.Add(cookie);
return RedirectToAction("Index", "Home");
}
Crear Vista de LOGIN y ERRORACCESO
VISTA LOGIN:
Copia siguiente código y sustituir todos los contenitos de la Vista de LOGIN
@{
ViewBag.Title = "Login";
}
<h2>Login de Usuario</h2>
@using (Html.BeginForm())
{
<div>
<label>Usuario :</label>
<input type="text" class="form-control" name="usuario" placeholder="Nombre de Usuario" />
</div>
<div>
<label>Password :</label>
<input type="password" class="form-control" name="password" placeholder="Clave de acceso" />
</div>
<br />
<div>
<button type="submit" class="btn btn-success">Login</button>
</div>
}
<h1 style="color:red">@ViewBag.Mensaje</h1>
VISTA ERRORACCESO:
Copia siguiente código y sustituir todos los contenitos de la Vista de ERRORACCESO
@{
ViewBag.Title = "ErrorAcceso";
}
<h2>ErrorAcceso</h2>
Crear Vista Parcial de CERRARSECION en SHARED
Copia siguiente código en tu Vista de CERRARSECION
@if (HttpContext.Current.User.Identity.IsAuthenticated)
{
<li>@Html.ActionLink("Cerrar sesion","CerrarSesion","Manage")</li>
}
En tu LAYAOUT añadir siguiente código en tu menú de navegación para mostrar la opción de cerrar sesión
@Html.Partial("_CerrarSesion")
Crear una carpeta Attribute y crear una clase con nombre de AutorizarAttribute
Elimina todos lo que tiene dentro del AutorizarAttribute copia siguiente código y pegarlo en AutorizarAttribute
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace post_Segurida_MVC.Attribute
{
public class AutorizarAttribute: AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
string controladorOrigen = filterContext.RouteData.Values["controller"].ToString();
string actionOrigen = filterContext.RouteData.Values["action"].ToString();
if (filterContext.HttpContext.Request.IsAuthenticated)
{
GenericPrincipal user = (GenericPrincipal)HttpContext.Current.User;
// aqui se puede un if para que limitar el acceso por role
//if (user.IsInRole("ADMIN") == false)
//{
// //nos lo llevamos a sin acceso
// RouteValueDictionary ruta = new RouteValueDictionary(new { Controller = "Manage", action = "ErrorAcceso" });
// filterContext.Result = new RedirectToRouteResult(ruta);
//}
}
else
{
filterContext.Controller.TempData["action"] = actionOrigen;
filterContext.Controller.TempData["controlador"] = controladorOrigen;
RouteValueDictionary rutalogin = new RouteValueDictionary(new { controller = "Manage", action = "Login" });
filterContext.Result = new RedirectToRouteResult(rutalogin);
}
}
}
}
Configurar Fichero GLOBAL.ASAX
copia siguiente código en tu Fichero de GLOBAL.ASAX
copia este método después del método de Application_Start
public void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpCookie cookie = Request.Cookies["Usuario"];
if (cookie != null)
{
string datos = cookie.Value;
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(datos);
string role = ticket.UserData;
GenericPrincipal principal = new GenericPrincipal(new GenericIdentity(ticket.Name), new string[] { role });
HttpContext.Current.User = principal;
}
}
Ultimo paso, aplicar el [Autorizar] en cualquier ACTION CONTROLADOR que quiere aplicarse la autenticación de seguridad.
Con esto cuando el usuario quiere acceder al ACTION que has aplicado la autenticación el proyecto va ha pedir que primero se inicia la sesión.
Si tiene cualquier duda vuelva al Principio de este BLOG Y léalo otra vez Paso a Paso
Volver a PrincipioAutor: YIBING JIN
Curso: Microsoft MCSA Web Applications + Microsoft MCSD App Builder + Xamarin
Centro: Tajamar
Año académico: 2019-2020
Linkedin Repository GITHUB