Implementar autorización en MVC .Net

Posted on Posted in .Net, MVC

Por default, los proyectos de MVC en .Net implementan una autorización y autenticación excelente, y es bueno usarlas cuando se puede, pero, no siempre se puede, a veces nuestros requerimientos son muy especiales, otras veces, los ambientes y el contexto nos limitan a implementar una autorización en MVC customizada.

Visual Studio por default nos asigna la autenticación de cuentas individuales, nosotros tenemos que cambiar esto presionando el botón de Change Autentication:

Cambiar autenticación y autorización en MVC
Cambiar autenticación y autorización en MVC

 

Después nos saldrá una ventana preguntándonos que tipo de autenticación queremos usar, donde elegiremos la primera, es decir No Authentication

Diferentes tipos de autenticación
Diferentes tipos de autenticación

 

ya que las otras son:

  • Individual User Accounts
    • Te permite usar cuentas de FB, Twitter, etc y registrar a los usuarios por medio de otros medios
    • La desventaja es que si es una aplicación donde varios usuarios no quieren o tienen cuentas en otros sitios, o si es intranet, difícilmente te va a funcionar.
  • Work and School accounts
    • Utiliza Active directory entre otras cosas, es muy útil cuando tienes todos los accesos controlados por este medio
    • Seria inútil si no los tienes controlados por Active directory o no todos están ahí
  • Windows authentication
    • Útil cuando todos tus usuarios tienen cuenta y acceso a una computadora dedicada para ellos
    • Inútil cuando mas de un usuario utiliza la misma computadora

Así que si nuestros requerimientos no encajan en ninguno de estos casos que tiene .Net podemos crear nuestro propio mecanismo de autorización en MVC muy simple.

Creando la sesión del usuario

Normalmente yo tengo una clase donde guardo todas las variables de sesion de la siguiente manera

public class Settings
{
	public static Models.User User
	{
		get { return HttpContext.Current.Session["UsuarioEnSession"] == null ? null : HttpContext.Current.Session["UsuarioEnSession"] as Models.User; }
		set { HttpContext.Current.Session["UsuarioEnSession"] = value; }
	}
}

De esta forma, cada vez que quiero acceder a alguna propiedad del usuario que esta en sesión solamente tengo que llamar a Settings.User y no tengo que andar casteando por todos lados del objeto de sesión al tipo de objeto que realmente es; es mas cómodo, entendible y extensible,

Para crear la sesión lo hago de la siguiente manera en la acción Login

[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult Login(string username, string password)
{
	// Validacion de los parametros
	
	// Validacion del username
	
	// Validacion del password
	
	// Si todo esta correcto entonces le asigno la variable user, 
	// que contiene al usuario que acaba de iniciar sesion
	Settings.User = user;
	return new JsonResult { Data = new { Success = true }, JsonRequestBehavior = JsonRequestBehavior.DenyGet };
}

Autorización en MVC usando decoradores

Ahora que ya tenemos al usuario en sesión es necesario crear la clase que autenticara a nuestros usuarios en las partes del sistema donde queremos limitar el acceso a personas con usuarios en la aplicacion o con ciertos roles. Primero crearemos la clase que hará la validación.

public class Authorization : AuthorizeAttribute
{
	// Aqui se valida si el usuario es valido
	protected override bool AuthorizeCore(HttpContextBase httpContext)
	{
		if (httpContext == null) throw new ArgumentNullException("httpContext");

		//  Si no hay ningun usuario en sesion regresa False
		if (Settings.User == null)
			return false;

		//  Si hay una sesion de usuario y no hay roles especificos requeridos, entonces regresa True
		var roles = this.Roles.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
		if (roles.Length == 0) return true;
		
		//  Si hay roles requeridos, valida que el usuario tenga un rol valido
		return roles.Contains(Settings.User.Role.Name);
	}

	// Este metodo se llama cuando el metodo de arriba regresa False, y lo que hace es que redirige al usuario a la pagina de inicio de sesion
	protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
	{
		var url = "/Home/Login";
		filterContext.Result = new RedirectResult(url);    
	}
}

Ya que tenemos la clase creada, ahora la usaremos en decoradores, estos decoradores son una sola linea de codigo que llamara a esta clase cada vez que alguien intente acceder a algun controlador o acción, y los usamos de la siguiente manera:

public class UsuariosController : Controller
{
	// Aqui solamente estamos pidiendo que valide que tenga
	// una sesion en el sistema
	[Authorization]
	public ActionResult Index()
	{
		return View();
	}

	// Pero aqui, estamos pidiendo que valide que tenga
	// una sesion en el sistema y que tenga un rol de 'Admin'
	[Authorization(Roles = "Admin")]
	public ActionResult IndexAdmin()
	{
		return View();
	}
}

En el ejemplo de arriba, pueden ver que estamos validando las dos acciones (métodos) para que solamente entren personas que tengan sesión en el sistema, aunque, un usuario con rol de admin podrá entrar a las dos acciones, pero un usuario que no es admin, solamente podrá acceder a la primera acción.

NOTAS

  • Los decoradores (las lineas arriba de los métodos) tambien pueden ser usados en todo un controlador, es decir, si lo pones justo arriba de UsuariosController, todas las acciones de ese controlador usaran las misma autenticación, de esta forma te evitas estar repitiendo en todas las acciones el mismo decorador, en caso de que sea exactamente el mismo.
  • Si vas a usar diferentes decoradores, por ejemplo algunas acciones de tu controlador solamente pueden ser accesados por el rol de admin, otras acciones por cualquier usuario y otras acciones incluso no necesitan autenticación, entonces te recomiendo que no pongas la validación en el controlador, si no especifica cada autenticación en cada acción de tu controlador si es que aplica.