SignalR y Authorize desde clientes .NET - Code Variables -->
Code Variables Code Variables

Latest news

جاري التحميل ...

SignalR y Authorize desde clientes .NET

SignalRComo comentamos por aquí hace tiempo, SignalR viene acompañado de su propia versión del atributo [Authorize], que permite restringir el acceso a hubs o a métodos concretos dentro de éstos de forma similar a como lo hacemos en otras tecnologías como ASP.NET MVC o Web API.

Si estamos trabajando en el entorno web, es decir, cuando cliente y servidor son puras tecnologías web y están ejecutándose en el mismo contexto, el servidor determina si el cliente SignalR está autenticado utilizando los mismos mecanismos de siempre, basados en la existencia de la cookie de autorización de ASP.NET y en los datos contenidos en ésta.

De esta forma, si un cliente entra con su navegador a nuestra web y supera el procedimiento de autenticación, a partir de ese momento todas sus peticiones llevarán adjunta la cookie de autorización, y ésta misma es la que usará SignalR para conceder o denegar el acceso a los métodos de los Hubs cuando accedamos a ellos usando el cliente Javascript.

Sin embargo, a través del formulario de contacto de Variable not found, me llega una consulta muy interesante del amigo Juan F.: ¿cómo podemos usar ese mismo atributo Authorize para controlar el acceso desde aplicaciones no web, las que usan el cliente genérico .NET de SignalR?

0. Solución conceptual

Como hemos comentado, SignalR permite indicar mediante el atributo Authorize que un método de un Hub puede ser ejecutado sólo por usuarios autenticados, o incluso especificar cuáles de ellos o sus roles:
[Authorize(Users="jmaguilar")]
public Task PrivateMessage(string message)
{
return Clients.All.Message(
DateTime.Now.ToLongTimeString() + " -> " + message);
}
Desde el punto de vista del servidor, la autorización se resuelve observando el IPrincipal asociado a la conexión física abierta con el servidor, disponible en la propiedad Context.User de la clase Hub. A su vez, éste IPrincipal es rellenado de forma automática por la plataforma a la vista de la información contenida en la cookie de autenticación, que normalmente viaja en las peticiones con el nombre .ASPXAUTH.

Está claro que la solución a la pregunta del amigo Juan pasa por obtener una de estas cookies que autorizan al usuario desde nuestra aplicación cliente .NET, y adjuntarla a la conexión que vamos a realizar al Hub. Se trata, por tanto, de un proceso previo a la apertura de la conexión con el Hub, más o menos con los siguientes pasos:
  1. Implementamos en el mismo servidor donde se encuentran los Hubs un método/acción/lo que sea capaz de autenticar al usuario y generar la cookie de autorización de ASP.NET.
     
  2. Creamos una conexión HTTP desde el cliente invocando a dicho método, al que suministramos las credenciales del usuario.
     
  3. Obtenemos la respuesta de dicha petición, y de ella extraemos el valor de la cookie .ASPXAUTH.
     
  4. Antes de iniciar la conexión con el Hub, adjuntamos la cookie a la petición para que el servidor nos reconozca.
Y esto sería todo. A partir de ese momento, el servidor ya tendría información suficiente como para permitir o denegar nuestra entrada al método o hub protegido por el atributo Authorize.

¿Algo lioso? Ya verás como no ;-)

1. Implementación de la autenticación (servidor)

Dado que la implementación depende de la tecnología (MVC, Webforms, Web API, WebPages…), vamos a simplificarla al máximo. Simplemente crearemos un archivo llamado Login.aspx, y en su code-behind introduciremos el siguiente código:
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
var username = Request["username"];
var password = Request["password"];

// In real code, we could check if this user exists
// in the database.

// For sake of brevity, we'll assume that the credentials
// are valid

FormsAuthentication.SetAuthCookie(username, false);
Response.End();
}
Obviamente, podríamos haber escrito el mismo código para MVC, en el interior de una acción:
public ActionResult Login(string userName, string password)
{
...
// If the credentials are valid:
FormsAuthentication.SetAuthCookie(userName, false);

return new EmptyResult();
}
En cualquiera de los dos casos, el resultado es el mismo: la petición se responderá con un contenido nulo, pero con una bonita cookie que contiene información del usuario autenticado en el sitio web :-)

2. Obtención de la cookie de autenticación (cliente)

Desde la aplicación .NET, a continuación vamos a implementar un método que realice una petición hacia la página .aspx (o la acción MVC, da igual) para validar las credenciales y obtener la cookie si se supera la autenticación. Esto podemos conseguirlo de muchas formas, la plataforma ofrece varias clases para realizar peticiones HTTP, pero WebClient parece una buena candidata para usar al facilitarnos el acceso directo a las cookies generadas por el servidor:
private static Cookie GetAuthCookie(string loginUrl, string user, string pass)
{
var url = loginUrl + "?username=" + user + "&password=" + pass;
var request = WebRequest.Create(url) as HttpWebRequest;
request.CookieContainer = new CookieContainer();
var httpResponse = request.GetResponse() as HttpWebResponse;
var cookie = httpResponse.Cookies[".ASPXAUTH"];
httpResponse.Close();
return cookie;
}
Este código podríamos mejorarlo bastante, por ejemplo, usando el verbo POST para enviar las credenciales. Sin embargo, he preferido dejarlo así para no hacerlo más extenso y que no nos distraiga de nuestro objetivo real.

3. Adjuntar la cookie al establecer la conexión con Signalr (cliente)

Ahora llega ya el momento de utilizar el método anterior en el proceso de establecimiento de la conexión del cliente SignalR. Tan sencillo como lo que vemos a continuación:
const string host = "http://myserver.com:1234";
var connection = new HubConnection(host);

Console.Write("Enter your username: ");
var username = Console.ReadLine();
Console.Write("Enter your password: ");
var password = Console.ReadLine();

// Get the cookie
var cookie = GetAuthCookie(host+"/login.aspx", username, password);

// Attach the cookie to the connection
connection.CookieContainer = new CookieContainer();
connection.CookieContainer.Add(cookie);

var proxy = connection.CreateHubProxy("EchoHub");

// ... other initialization code

// And, finally, start the connection
connection.Start();
Como podemos observar, el código es absolutamente trivial. El objeto HubConnection de SignalR dispone de una propiedad llamada CookieContainer donde podemos establecer las cookies que deseamos viajen al servidor durante el establecimiento de la conexión. Introducimos ahí la cookie de autorización obtenida previamente, y ¡listo!

A partir de este momento, ya podremos acceder a todos los métodos o Hubs protegidos mediante el atributo [Authorize], e incluso acceder a ellos si somos los usuarios específicamente autorizados.

Si os interesa verlo en acción, podéis descargar un proyecto de demostración desde mi Skydrive.

Publicado en Variable not found.

Comments



If you like the content of our blog, we hope to stay in constant communication, just enter your email to subscribe to the blog's express mail to receive new blog updates, and you can send a message by clicking on the button next ...

إتصل بنا

About the site

author Code Variables  Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

Learn more ←

Blog visitors

Blog stats

All Copyrights Reserved

Code Variables

2019