I am working on an ASP.NET website which uses forms authentication with a custom authentication mechanism (which sets e.Authenticated
programmatically on protected void Login_Authenticate(object sender, AuthenticateEventArgs e)
).
I have an ASP.NET sitemap. Some elements must be displayed only to logged in users. Others must be displayed only to one, unique user (ie. administrator, identified by a user name which will never change).
What I want to avoid:
- Set a custom role provider: too much code to write for a such basic thing,
- Transform the existing code, for example by removing sitemap and replacing it by a code-behind solution.
What I want to do:
- A pure code-behind solution which will let me assign roles on authenticate event.
Is it possible? How? If not, is there an easy-to-do workaround?
As Matthew says, building a principal and setting it yourself at the right moment is the easiest way to take advantage of all of the built in Role based goodies like SiteMap.
But there is a much easier standards based method of implementing this than shown by MSDN.
This is how I implement a simple role provider
Global.asax
using System;
using System.Collections.Specialized;
using System.Security.Principal;
using System.Threading;
using System.Web;
using System.Web.Security;
namespace SimpleRoles
{
public class Global : HttpApplication
{
private static readonly NameValueCollection Roles =
new NameValueCollection(StringComparer.InvariantCultureIgnoreCase)
{
{"administrator", "admins"},
// note, a user can be in more than one role
{"administrator", "codePoets"},
};
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
HttpCookie cookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
Context.User = Thread.CurrentPrincipal =
new GenericPrincipal(Context.User.Identity, Roles.GetValues(ticket.Name));
}
}
}
}
To manually check the user in the context of a Page codebehind:
if (User.IsInRole("admins"))
{
// allow something
}
Elsewhere just get the user off of the current context
if (HttpContext.Current.User.IsInRole("admins"))
{
// allow something
}
I use this technique which microsoft recommends:
http://msdn.microsoft.com/en-us/library/aa302399.aspx
In global asax I intercept the auth cookie, and then set the thread principle and the HttpContext user and the roles for the same. After you can use HttpContext.Current.User.IsInRole("foo"), which is much the same sort of code you would use in the WinForm equivallent.
The more you can rely on built in patterns, the more likely it will be secure and the more likely the maintenance developer will recognize how to use the pattern.