|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThe current implementation of ASP.NET 2.0's security is great and I have fallen in love with it, but it's still too limited. I will show you how to extend ASP.NET 2.0's security using a custom HTTP Module and your existing Web.sitemap. This article will show you how to secure individual pages, each with independent permissions, without the need to add redundant data into your web.config. AssumptionsThis article assumes you are already familiar with ASP.NET 2.0's built-in user and role based security. This article also assumes you are familiar with ASP.NET 2.0's Web.sitemap. Familiarity with C# is a bonus, but not required. I'm also assuming your site is already setup and using forms authentication. The ProblemASP.NET 2.0 gives you this great tool to make securing directories easy, and it does a great job. You are also given a Web.sitemap file that allows you to restrict access by roles. <?xml version="1.0" encoding="utf-8" ?>
<siteMap>
<siteMapNode url="Default.aspx" title="Home"
description="This is the default page">
<siteMapNode url="Webform1.aspx" title="Webform1" description="">
<siteMapNode url="Marketing/SecureFile.aspx" title="Secure File 1"
description="" roles="Marketing" />
</siteMapNode>
<siteMapNode url="" title="Marketing">
<siteMapNode url="SecureFile.aspx" title="Secure File 2"
description="" roles="Marketing" />
</siteMapNode>
<siteMapNode url="" title="Links">
<siteMapNode url="http://google.com" title="Google"
description="Google" roles="" target="_blank" />
<siteMapNode url="http://yahoo.com" title="Yahoo!"
description="Yahoo!" roles="" target="_blank" />
<siteMapNode url="http://microsoft.com" title="Microsoft"
description="Microsoft" roles="" target="_blank" />
</siteMapNode>
</siteMapNode>
</siteMap>
Unfortunately, only the ASP.NET 2.0 site navigation controls use the Web.sitemap If you go directly to the URL of a file in the Web.sitemap that has roles, it will not be restricted by those roles (though, it'd be nice if it did). The SolutionThe solution is to implement your own HTTP Module and determine the allow / deny security based upon the Add the following code to your web.config file inside the <httpModules>
<add name="SecurityHttpModule" type="Joel.Net.SecurityHttpModule" />
</httpModules>
Here's the code that performs all the magic... using System;
using System.Web;
using System.Web.Security;
namespace Joel.Net {
/// <summary>Security Http Module</summary>
public class SecurityHttpModule : IHttpModule {
public SecurityHttpModule() { }
/// <summary>Initializes a module and prepares
/// it to handle requests.</summary>
/// <param name="context"
/// >An <see cref="T:System.Web.HttpApplication" />
/// that provides access to the methods, properties,
/// and events common to all application objects within
/// an ASP.NET application </param>
public void Init(System.Web.HttpApplication context) {
context.AuthenticateRequest += new
EventHandler(this.AuthenticateRequest);
}
/// <summary>Occurs when a security module
/// has established the identity of the user.</summary>
private void AuthenticateRequest(Object sender, EventArgs e) {
HttpApplication Application = (HttpApplication)sender;
HttpRequest Request = Application.Context.Request;
HttpResponse Response = Application.Context.Response;
bool allow = false; // Default is not not allow
// Exit if we're on login.aspx,
// not authenticated, or no siteMapNode exists.
if (Request.Url.AbsolutePath.ToLower() ==
FormsAuthentication.LoginUrl.ToLower()) return;
if (Application.Context.User == null)
Response.Redirect(FormsAuthentication.LoginUrl);
if (SiteMap.CurrentNode == null) return;
// Check if user is in roles
if (SiteMap.CurrentNode.Roles.Count == 0) {
allow = true; // No Roles found, so we allow.
} else {
// Loop through each role and check to see if user is in it.
foreach (string role in SiteMap.CurrentNode.Roles) {
if (Roles.IsUserInRole(role)) { allow = true; break; }
}
}
// Do we deny?
if (allow == false)
Response.Redirect(FormsAuthentication.LoginUrl);
}
/// <summary>Disposes of the resources (other than memory)
/// used by the module that implements
/// <see cref="T:System.Web.IHttpModule" />.</summary>
public void Dispose() { }
}
}
Inside the The first block of code sets up all the objects we'll need, The following block will exit, or allow access (allowing access only means our custom HTTP module permits it, it still has to pass ASP.NET 2.0's security restrictions), under three conditions:
Next, we loop through each role in the current Lastly, we test our ' SummaryWe created an easy way (only approx. 55 lines of code) to extend ASP.NET 2.0's security, while still allowing ASP.NET 2.0 to control the security. When our HTTP Module cannot handle a request (e.g.: user not logged in, page not in Web.sitemap), we simply pass the request off to ASP.NET 2.0 and let it handle the security. Resources | ||||||||||||||||||||