Control de acceso a Hubs SignalR

 

SignalR

SignalR permite controlar el acceso a los métodos del interior los Hubs de una forma muy similar a como hacemos en ASP.NET MVC o WebAPI.

Y cuando digo muy similar no estoy exagerando en absoluto, como podéis observar en el siguiente código:

1
2
3
4
5
6
7
8
[Authorize]
public class AlertService : Hub
{
    public void Alert(string msg)
    {
        this.Clients.All.showAlert(msg);
    }
}

imagePues sí, también tenemos disponible aquí el atributo [Authorize]. O mejor dicho, otro atributo [Authorize]. Cuidado con esto, porque en un proyecto MVC4 con WebAPI y SignalR tendremos a nuestra disposición tres atributos con el mismo nombre, y si seleccionamos el namespace incorrecto será ignorado por completo, dejando libre el acceso al recurso que se intenta proteger.

¿Recordáis el famoso infierno de las DLL de antaño? Pues no va a ser nada comparado con el namespace hell que se está cociendo ;-D

Bueno, la cuestión es que aplicando este atributo a un Hub de la forma mostrada anteriormente impediremos el acceso a sus métodos a clientes que no hayan sido autenticados en el sistema. Si únicamente queremos efectuar este control en métodos concretos, bastará con decorarlos con [Authorize] de forma individualizada:

1
2
3
4
5
6
7
8
9
10
public class AlertService: Hub
{
    [Authorize]
    public void Alert(string msg)
    {
        this.Clients.All.showAlert(msg);
    }
 
    // Other hub methods
}

A la hora de introducir el atributo podemos ser aún más explícitos. Así, es posible permitir el acceso a un Hub o método a uno o varios usuarios separando su nombre por comas:

1
2
3
4
5
[Authorize(Users="fmercury,mjackson,fsinatra")]
public void Sing(string msg)
{
    // ...
}

O también podemos hacerlo por roles dentro del sistema:

1
2
3
4
5
[Authorize(Roles= "greatsingers")]
public void Sing(string msg)
{
    // ...
}

Por último, comentar que a diferencia de los homónimos atributos usados en MVC y WebAPI, este nuevo Authorize dispone de un parámetro booleano adicional llamado RequireOutGoing que si establecemos a falso hará que las peticiones al método afectado sean ejecutadas sin necesidad de autenticación.

Publicado en Variable not found.

CDN con fallbacks en bundles

ASP.NETLa nueva versión de System.Web.Optimization traerá (aún está en beta) algunas novedades interesantes al sistema de bundling que se incluye de serie en los proyectos ASP.NET MVC y se distribuye a través de Nuget en el paquete Microsoft.AspNet.Web.Optimization.

En particular, vamos a centrarnos en una característica muy práctica si queremos utilizar una Content Delivery Network (CDN) externa (como la de Microsoft, Google o incluso una propia) para delegar a ella la carga de bibliotecas de script comunes, pero queremos a la vez proporcionar una alternativa local por si acaso ésta fallase debido a cualquier motivo.

1. La situación actual

El sistema de bundling ya nos permitía, al mismo tiempo que definíamos los bundles, especificar la dirección en la CDN a través de la cual el archivo podía ser obtenido. Esto lo hacíamos justo en el momento de la creación del bundle:

1
2
3
4
5
bundles.Add(new ScriptBundle(
        "~/bundles/jquery", // Bundle virtual path
    )
    .Include("~/Scripts/jquery-{version}.js"));

Este bundle podemos referenciarlo desde la vista usando la dirección virtual asignada como sigue:

1
2
3
4
      ...
      @Scripts.Render("~/bundles/jquery")
   </body>
</html>

El código resultante de esta llamada depende del valor establecido en la propiedad booleana BundleTable.Bundles.UseCdn . Si contiene false, el valor por defecto, el tag <script> generado apunta a la dirección del servidor local a través de la cual es posible descargar el archivo comprimido:

1
<script src="/bundles/jquery?v=UgyEMAYOuSB9Bb6HcOEVHpd6fIIp54yF086SRNVcdIY1"></script>

En cambio, si el valor de BundleTable.Bundles.UseCdn es true, la URL que aparecerá en el tag es la indicada como dirección del archivo en el CDN:

2. Las novedades

Lo anterior está bien pero, aunque puede resultar válido en muchos escenarios, hay casos en los que es claramente insuficiente y tenemos que hacer algunos apaños para que todo vaya bien. Sólo tenéis que imaginar que estamos desarrollando una aplicación con esas referencias en un ordenador sin internet…

Pues para evitarnos trabajo, la nueva versión de System.Web.Optimization incluye un mecanismo automático de fallback que nos permite detectar cuándo ha habido problemas descargando nuestra biblioteca desde el CDN, y, en este caso, cargar el bundle local de forma automática.

La forma de conseguirlo es idéntica a la de antes: definimos un bundle de un archivo especificando la dirección de la URL para obtenerlo desde la CDN, e indicamos en él una expresión de fallback, es decir, una expresión que será evaluada en tiempo de script y que debe determinar si la biblioteca ha sido cargada con éxito. Por ejemplo, para saber si jQuery ha sido cargado con éxito sólo hay que observar si hay un objeto en window.jQuery, ¿verdad? Pues esa sería la expresión de fallback.

El siguiente ejemplo muestra cómo deberíamos crear el bundle y añadirlo a la tabla de bundles del sistema especificando la expresión de comprobación:

1
2
3
4
5
6
7
8
var jquery = new ScriptBundle(
        "~/bundles/jquery", // Bundle virtual path
    )
    .Include("~/Scripts/jquery-{version}.js");
 
jquery.CdnFallbackExpression = "window.jQuery";
BundleTable.Bundles.Add(jquery);

Una vez referenciado en la vista, el código de marcado generado será el siguiente:

1
2
<script>(window.jQuery)||document.write('<script src="/bundles/jquery"></script>');</script>

Observad que lo único que se hace es introducir un bloque de script justo después de la referencia al CDN en el que se evalúa la expresión de fallback y, si no se cumple, se genera sobre la página una nueva referencia al bundle local. Si queréis comprobar su funcionamiento, sólo tenéis que introducir una dirección incorrecta en la URL al CDN, y veréis cómo se utiliza el archivo local.

Por último, indicar que podéis probar estas cosas descargando desde Nuget la versión prerelease del paquete. Ah, y recordad que para que el bundling funcione correctamente es necesario desactivar el modo depuración en el web.config, o bien habilitar manualmente este mecanismo introduciendo la siguiente asignación en algún punto de la inicialización de la aplicación:

1
BundleTable.EnableOptimizations = true;

En definitiva, es algo que ya podíamos solucionar desde la primera versión de forma manual, pero que ahora lo tendremos más fácil al venir integrado en el producto 🙂

Publicado en Variable not found.