Jeg har tidligere skrevet en post omkring HttpHandlers i IIS 7.x. Denne gang vil jeg forsøge at forklare jer lidt omkring hvad et HttpModule er og hvad man kan få ud af at bruge det.
Et HttpModule er, ligsom en HttpHandler en mulighed for at extende Windows webserveren, IIS. Forskellen på en Handler og et Module er at man i et Module for det første er et ligner ISAPI filter hvorimod en Handler ligner en ISAPI extension. Når jeg skriver “ligner” i denne sammenhæng er det fordi, at ISAPI filtre samt extensions ikke længere behøver at være skrevet i unmanaged kode, og at både “request pipelinen” samt hele IISn er lavet om, så man nu kan tilgå den og dens features via ren .NET. På den måde kan man altså extende sin webserver med lethed.
Inden vi går videre skal du måske lige have en opfrisker….kan du huske hvad der sker når der bliver lavet et request til f.eks ASP.NET ?
En af de fede ting ved IIS 7.x er at ASP.NET runtimen er blevet bygget ind i webserveren. Det betyder bla. at der er én og kun én “request cycle pipeline” for alle requests. Det kommer vi til at se nærmere på lige om lidt.
Du skal bruge HttpModules fordi…
1. Den samme pipeline raiser alle de events som er bygget ind i HttpApplication typen. Det gør det muligt at bygge egne HTTP moduler og handlers til IIS med .NET.
2. Både (un)managed HTTP moduler og handlers kan sættes på webserver, website eller applikations niveau.
3. Managed HTTP moduler kan kaldes på hvilket som helst tidspunkt i "request cycle pipelinen”. Både før og efter serveren rent faktisk gør noget ved selve requestet.
Lad os se på hvordan du laver et HttpModule. Du skal ligsom med en HttpHandler implementere et interface. Interfacet for HttpModuler hedder IHttpModule og giver dig 2 ting. Init og Dispose.
Jeg har stjålet lidt kode fra Mads Kristensens blog da han har skrevet utrolig meget omkring både HttpHandlers og HttpModules.
using System;
using System.Web;
using System.Configuration;
using System.Collections.Specialized;
public class IpBlockingModule : IHttpModule
{
void IHttpModule.Dispose()
{
// Nothing to dispose;
}
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
private void context_BeginRequest(object sender, EventArgs e)
{
string ip = HttpContext.Current.Request.UserHostAddress;
if (_IpAdresses.Contains(ip))
{
HttpContext.Current.Response.StatusCode = 403;
HttpContext.Current.Response.End();
}
}
private static StringCollection _IpAdresses = FillBlockedIps();
private static StringCollection FillBlockedIps()
{
StringCollection col = new StringCollection();
string raw = ConfigurationManager.AppSettings.Get("blockip");
raw = raw.Replace(",", ";");
raw = raw.Replace(" ", ";");
foreach (string ip in raw.Split(';'))
{
col.Add(ip.Trim());
}
return col;
}
}
Ovenstående HttpModule er ikke til noget nytte medmindre du også har implementeret den rigtige appsetting samt registret den i din applikation eller på website/server niveau.
<appSettings>
<add key="blockip" value="44.0.234.122, 23.4.9.231"/>
</appSettings>
<system.webServer>
<modules>
<add name="IpBlocking" type="IpBlockingModule" />
</modules>
</system.webServer>
Som i kan se så er der lavet et “hook” ind i request pipelinen, ved den event der hedder BeginRequest (kig i Init metoden). Dette modul bliver tilføjet til den bunken med de andre moduler som et request skal igennem, og i dette tilfælde vil hvert request blive tjekket med denne IpBlocking rutine som
Mads har været så rar at skrive.
Hvis du ikke allerede har extended din IIS webserver så er det med at komme igang ;0)