Archiv für 29. Oktober 2009

Routing mit ASP.NET WebForms, Teil 2

Donnerstag, 29. Oktober 2009

In Teil 1 ging es darum, wie die ASP.NET 3.5 Routing Engine in einer WebForms Applikation genutzt werden kann. Angeschaut wurde die Konfiguration der Applikation für die Engine, und das Definieren und Auswerten eigener Routen.
In diesem zweiten Teil werden nun die Security Aspekte angeschaut.

Das Routing Modul verarbeitet die Events in der Request Pipeline nachdem die Authentisierung und Autorisierung bereits stattgefunden hat. Das bedeutet, dass die Benutzer anhand der sichtbaren URL autorisiert werden und nicht über den virtuellen Pfad zum WebForm.

Wenn also der Zugriff auf unsere Beispiel URL “customer/” nur authentisierten Benutzern gestattet sein soll, kann dies über einen Eintrag im Root web.config erreicht werden:

<location path="customer">
  <system.web>
    <authorization>
      <deny users="?" />
    </authorization>
  </system.web>
</location>

Anonyme Benutzer der Applikation können nun nicht mehr auf Adressen wie “customer” oder “customer/42″ zugreifen, sondern werden auf eine Login Seite umgeleitet. Diese enthält sogar den Pfad unserer Route:

Login mit Return URL

Login mit Return URL

Nun muss noch sichergestellt werden, dass die Authorisation Prüfung über den virtuellen Pfad erfolgt, den der RouteHandler verwendet. Die Methode GetHttpHandler sieht also wie folgt aus:

public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
    if (!UrlAuthorizationModule.CheckUrlAccessForPrincipal(_virtualPath, requestContext.HttpContext.User, requestContext.HttpContext.Request.HttpMethod))
    {
        requestContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        requestContext.HttpContext.Response.End();
    }

    var page = BuildManager.CreateInstanceFromVirtualPath(_virtualPath, typeof(Page));

    var queryString = new StringBuilder("?");
    foreach (var rdv in requestContext.RouteData.Values)
    {
        queryString.Append(requestContext.HttpContext.Server.UrlEncode(rdv.Key));
        queryString.Append("=");
        queryString.Append(requestContext.HttpContext.Server.UrlEncode(rdv.Value.ToString()));
        queryString.Append("&");
    }
    queryString.Remove(queryString.Length - 1, 1);

    HttpContext.Current.RewritePath(string.Concat(_virtualPath, queryString));

    return (IHttpHandler)page;
}

Eine letzte Einstellung ist noch nötig. Anonyme Benutzer können immer noch direkt über den physikalischen Pfad (z.B. ~/Customers/CustomerDetail.aspx) auf die WebForms zugreifen. Dies kann verhindert werden, indem eine web.config Datei im entsprechenden Verzeichnis angelegt wird:

<configuration>
  <system.web>
    <authorization>
      <deny users="?" />
    </authorization>
  </system.web>
</configuration>

Ich habe ein Beispielprojekt zusammengestellt, welches alle besprochenen Elemente zeigt: RoutingWebApplication.zip