Introduction
Forms authentication enables user and password validation for Web applications that do not require Windows authentication. With forms authentication, user information is stored in an external data source, such as a Membership database, or in the configuration file for an application. Once a user is authenticated, forms authentication maintains an authentication ticket in a cookie or in the URL so that an authenticated user does not need to supply credentials with each request.
At my web site, I have a folder "Admin", which I only want users with administration roles to be able to access. I simply don't want to check each user's right on this folder, just depends on roles. This article is about this approach.
Background
In my case, I don't care who has logged into my website, if they are not logged in, they can only browse my web site; if they registered and logged in, they can do certain things, like add a fire panel, delete the fire panel they created; if users logged in with administration roles, web site will grant them rights to access files under "admin" folder.
Using the Code
Download the code, unzip it to a folder, create a virtual directory on IIS for it. Root directory contains "login.aspx","logout.aspx","default.aspx", and a folder called "admin". At "admin", there is only one file, "default.aspx" - this is the file I will stop normal user from accessing.
Forms authentication includes several important parts you need to implement.
At my web.config file, I set Authentication mode to "Forms".
At web.config, I create a folder that I want to authenticate user as follows:
<location path="Admin">
<system.web>
<authorization>
<allow roles="Administrators"/>
<deny users ="*"/>
</authorization>
</system.web>
</location>
<authentication mode="Forms">
<forms name="AuthCookie" path="/" loginUrl="login.aspx"
protection="All" timeout="30">
</forms>
</authentication>
Please remember to put <allow roles="Administrators" />
before <deny users="*" />
, otherwise no one will be able to access folder "admin".
Forms authentication "login
" URL is "login.aspx", you can change whatever file you like.
At credentials section, I used to have several users that I want to authenticate, and use asp:LoginView
web control to show their login status, it turn out to be not very flexible. I abandoned it, instead by using Roles, and this is where this article comes from. This way I can create users, save them to database, assign them "Administrators" roles, they will be able to access my "Admin" folder.
OK, the next thing is to create a web site structure. Here I used "web.sitemap
", you can add it by selecting Visual Studio 2008's add new item option.
At "web.sitemap" file, I created several SiteMapNode
with "Administrators" roles as follows:
="1.0"="utf-8"
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="~" title="Home" description="">
<siteMapNode url="default.aspx" title="Home" description="" roles="*"/>
<siteMapNode url="login.aspx" title="Login" description="" roles="*"/>
<siteMapNode url="Admin/" title="Administration" description="" roles ="*" >
<siteMapNode url="Admin/default.aspx" title="Administration"
description="" roles ="Administrators" />
</siteMapNode>
<siteMapNode url="logout.aspx" title="Logout" description="" roles="*"/>
</siteMapNode>
</siteMap>
In my default.aspx, I used Repeater
, and SiteMapDataSource
controls to make my web site more maintainable. On my real web site, I used Repeater
, SiteMapDataSource
and SiteMapPath
controls at master page, which makes the whole web site look more clean and tidy.
When the user first sees this web site, they can see "Administration" hyperlink, click on it, IIS's FormsAuthentication
object will navigate user to "login.aspx" page because of "Web.Config" file's setting, asking user to Login.
Type in user name, password, check it through various methods, database access in my case, user authenticated, grant certain user "Administrators" roles as follows:
FormsAuthenticationUtil.RedirectFromLoginPage("Lewis", "Administrators", true);
FormsAuthenticationUtil is a third party DLL, it creates an authentication ticket for user, change user's log in status to Logged In. Later on, I stopped using this DLL. Because I need to have full control of user's Login process.
I created a User class which especially handles user's Login and Registration process, etc. A snippet of code:
public static void CreateTicket(ENetUser newUser,bool persistantCookie)
{
string roles = "users";
if (newUser.Email.ToLower().Trim() == "abc@hotmail.com" ||
newUser.Email.ToLower().Trim() ==
"john.dole@pertronic.co.nz") roles = "Administrators";
roles += "," + newUser.ID;
roles += "," + newUser.ID;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1,
newUser.UserName,
DateTime.Now,
DateTime.Now.AddMinutes(30),
persistantCookie,
roles,
FormsAuthentication.FormsCookiePath);
string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(
FormsAuthentication.FormsCookieName,
hash);
if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;
System.Web.HttpContext.Current.Response.Cookies.Add(cookie);
}
As you can see, I created a ticket for user, add a cookie to user's PC. When user accesses our web site the next time, we recreate the user's ticket from that Cookie.
The above code is not in the example code, it is a hint "FormsAuthenticationUtil
" is done, I think.
The next thing is that you need to tell the web application how to authenticate users. I added the following lines to global.asax, if you do not have that file in your web root directory, add it by selecting "add new item" from Visual Studio 2008 "Web Site" menu.
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (HttpContext.Current.User != null)
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
{
if (HttpContext.Current.User.Identity is FormsIdentity)
{
FormsIdentity id =
(FormsIdentity)HttpContext.Current.User.Identity;
FormsAuthenticationTicket ticket = id.Ticket;
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
}
As you can see, once users have logged in, they will be authenticated, but they do not have our "Administrators" roles yet. We use the above routine assign that role.
We are done.
As I mentioned above, the example didn't show how to read the above cookies from PC. The reason I need to do this is that I want to save user's time of logging in each time they opened up my web site.
At my web site, the following code was added to "global.asax", at session start, read cookie, give user a ticket, Application authenticate method will use that ticket to grant user "administrators" role.
void Session_Start(object sender, EventArgs e)
{
HttpCookie cookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
}
}
FormsAuthentication.FormsCookieName
is defined in web.config's "Forms" section.
History
- 26th August, 2010: Initial post