Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Forms Authentication in ASP.NET can be a powerful feature. With very little code and effort, you can have a simple authentication system that is platform-agnostic. If your needs are more complex, however, and require more efficient controls over assets, you need the flexibility of groups. Windows Authentication gives you this flexibility, but it is not compatible with anything but Internet Explorer since it uses NTLM, Microsoft's proprietary authentication system. Now you must choose how to manage your assets: provide multiple login pages / areas and force users to register for each, or assign groups to users and limit access to pages / areas to particular groups. Obviously, you must choose the latter.

Role-based security in Forms Authentication is one thing Microsoft left out in this round for .NET, but they didn't leave you high-and-dry. The mechanisms are there, they're just not intuitive to code. This tutorial will cover the basics of Forms Authentication, how to adapt it to make use of role-based security, and how to implement role-based security on your site with single sign-ons.

Updated: With ASP.NET 2.0, Microsoft introduced built-in support for role membership. If you're using ASP.NET 2.0 or newer it's recommended you read Managing Authorization using Roles on MSDN. You can use an abstract data provider or create your own. This article was written for ASP.NET 1.0 but will also work for 1.1.

Prerequisites

This tutorial is all about role-based security with Forms Authentication, a detail that Microsoft left out of .NET for this round. This tutorial will use different techniques that are almost completely incompatible with the standard Forms Authentication, save the setup, which we'll cover shortly.

To follow along in this tutorial, you'll need to create a database, a web application, several secured directories, and a few ASP.NET Web Forms (pages).

Creating the Database

We will create a simple database containing a flat table for this tutorial. Using the <credentials/> section of the Web.config file is not an option because no mechanism for roles is supported. For the purposes of brevity, the table we create will be very simple. You're welcome to expand the database to make use of relations (what I would do and actual do use on several sites) for roles. The implementation does start to get a little messy depending on how you do it, and the details are left up to you. This is merely a tutorial about developing role-based security.

So, choose what database management system you want to use (DBMS). For this tutorial, we'll choose the Microsoft Data Engine (MSDE) available with Visual Studio .NET, Office XP Developer, and several other products. We'll add one database, say web, and then add one table, say users. To the users table, we'll add three fields: username, password, and roles. Set the username field to the primary key (since it'll be used for look-ups and needs to be unique), and optionally create an index on the username and password fields together. If you're using Table-creation SQL Scripts, your script might look something like this:

CREATE 
DATABASE web

CREATE TABLE users
(
    username nvarchar(64) CONSTRAINT users_PK PRIMARY KEY,
    password nvarchar(128),
    roles nvarchar(64)
)

CREATE INDEX credentials ON users
(
    username,
    password
)

Feel free to add some credentials to your database, picking a few roles you think are good group names for your site, such as "Administrator", "Manager", and "User". For this tutorial, put them in comma-delimited format in the "roles" field like the following, pipe-delimited (|) table:

username|password|roles
"hstewart"|"codeproject"|"Administrator,User"
"joe"|"schmoe"|"User"

Take note to make the roles case-sensitive. Now let's move on to creating our pages necessary for role-based Forms Authentication.

Creating the Login Pages

If you haven't already done so, create a new Web Application, or attach to an existing Web Application, such as your web server's document root, "/". For this tutorial, we'll assume the Web Application resides in "/", though the procedure for any Web Application is the same.

Before we create any pages or setup our Web.config file, you must understand one thing: the login.aspx (or whatever you call your login page) must be public. If it isn't, your users will not be able to log-in, and could be stuck in an infinite loop of redirects, though I've not tested this and don't care to. So, this tutorial will assume that login.aspx is in "/", while we have two secured sub-directories, users and administrators.

First, we must create a Forms Authentication login system that supports roles. Because Microsoft did not provide for this easily, we will have to take over the process of creating the authentication ticket ourselves! Don't worry, it's not as hard as it sounds. A few pieces of information are needed, and the cookie has to be stored under the right name - the name matching the configured name for Forms Authentication in your root Web.config file. If these names don't match, ASP.NET won't find the Authentication Ticket for the Web Application and will force a redirect to the login page. For simplicity, we will put the code directly into the ASP.NET Web Form, which is easier to code for DevHood and should look something like the following:

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<html>
<head>
    <title>Login</title>
</head>
<script runat="server">
// If you're using code-behind, make sure you change "private" to
// "protected" since the .aspx page inherits from the .aspx.cs
// file's class
private void btnLogin_Click(Object sender, EventArgs e)
{
    // Initialize FormsAuthentication, for what it's worth
    FormsAuthentication.Initialize();

    // Create our connection and command objects
    SqlConnection conn =
     new SqlConnection("Data Source=localhost;Initial Catalog=web;");
    SqlCommand cmd = conn.CreateCommand();
    cmd.CommandText = "SELECT roles FROM web WHERE username=@username " +
     "AND password=@password";

    // Fill our parameters
    cmd.Parameters.Add("@username", SqlDbType.NVarChar, 64).Value =
Username.Value;
    cmd.Parameters.Add("@password", SqlDbType.NVarChar, 128).Value =
     FormsAuthentication.HashPasswordForStoringInConfigFile(
        Password.Value, "md5"); // Or "sha1"

    // Execute the command
    conn.Open();
    SqlDataReader reader = cmd.ExecuteReader();
    if (reader.Read())
    {
     // Create a new ticket used for authentication
     FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
        1, // Ticket version
        Username.Value, // Username associated with ticket
        DateTime.Now, // Date/time issued
        DateTime.Now.AddMinutes(30), // Date/time to expire
        true, // "true" for a persistent user cookie
        reader.GetString(0), // User-data, in this case the roles
        FormsAuthentication.FormsCookiePath);// Path cookie valid for

     // Encrypt the cookie using the machine key for secure transport
     string hash = FormsAuthentication.Encrypt(ticket);
     HttpCookie cookie = new HttpCookie(
        FormsAuthentication.FormsCookieName, // Name of auth cookie
        hash); // Hashed ticket

     // Set the cookie's expiration time to the tickets expiration time
     if (ticket.IsPersistent) cookie.Expires = ticket.Expiration;

     // Add the cookie to the list for outgoing response
     Response.Cookies.Add(cookie);

     // Redirect to requested URL, or homepage if no previous page
     // requested
     string returnUrl = Request.QueryString["ReturnUrl"];
     if (returnUrl == null) returnUrl = "/";

     // Don't call FormsAuthentication.RedirectFromLoginPage since it
     // could
     // replace the authentication ticket (cookie) we just added
     Response.Redirect(returnUrl);
    }
    else
    {
     // Never tell the user if just the username is password is incorrect.
     // That just gives them a place to start, once they've found one or
     // the other is correct!
     ErrorLabel = "Username / password incorrect. Please try again.";
     ErrorLabel.Visible = true;
    }

    reader.Close();
    conn.Close();
}
</script>
<body>
    <p>Username: <input id="Username" runat="server"
type="text"/><br />
    Password: <input id="Password" runat="server" type="password"/><br
/>
    <asp:Button id="btnLogin" runat="server" OnClick="btnLogin_Click"
     Text="Login"/>
    <asp:Label id="ErrorLabel" runat="Server" ForeColor="Red"
     Visible="false"/></p>
</body>
</html>

You'll notice above that we do one other thing with our passwords: we hash them. Hashing is a one-way algorithm that makes a unique array of characters. Even changing one letter from upper-case to lower-case in your password would generate a completely different hash. We'll store the passwords in the database as hashes, too, since this is safer. In a production environment, you'd also want to consider having a question and response challenge that a user could use to reset the password. Since a hash is one-way, you won't be able to retrieve the password. If a site is able to give your old password to you, I'd consider steering clear of them unless you were prompted for a client SSL certificate along the way for encrypting your passphrase and decrypting it for later use, though it should still be hashed.

Note: without using HTTP over SSL (HTTPS), your password will still be sent in plain-text across the network. Hashing the password on the server only keeps the stored password secured. For information about SSL and acquiring a site or domain certificate, see http://www.versign.com or http://www.thawte.com.

If you don't want to store hashed passwords in the database, change the line that reads FormsAuthentication.HAshPasswordForStoringInConfigFile(Password.Value, "md5") to just Password.Value.

Next, we'll need to modify the Global.asax file. If your Web Application doesn't have one already, right-click on the Web Application, select "Add->Add New Item...->Global Application Class". In either the Global.asax or Global.asax.cs (or Global.asax.vb, if you're using VB.NET), find the event handler called Application_AuthenticateRequest. Make sure it imports / uses the System.Security.Principal namespace and modify it like so:

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;

        // Get the stored user-data, in this case, our roles
        string userData = ticket.UserData;
        string[] roles = userData.Split(',');
        HttpContext.Current.User = new GenericPrincipal(id, roles);
     }
    }
  }
}

What's happening above is that since our principal (credentials - which are your username and roles) is not stored plainly as part of our cookie (nor should it, since a user could modify their list of role-memberships), it needs to be generated for each request. The FormsAuthenticationTicket is actually encrypted as part of a cookie using your machine key (usually configured in machine.config) and the FormsAuthentication module decrypts the tick as part of the user's identity. If you search long and hard enough on Microsoft MSDN web site, you'll find this documentation buried. We use the UserData to obtain the list of roles and generate a new principal. Once the principal is created, we add it to the current context for the user, which the receiving page can use to retrieve credentials and role-memberships.

Securing Directories with Role-based Forms Authentication

To make the role-based authentication work for Forms Authentication, make sure you have a Web.config file in your Web Application root. For the authentication setup, this particular Web.config file must be in your Web Application's document root. You can override the <authorization/> in Web.config files for sub-directories.

To begin, make sure your Web.config file has at least the following:

<configuration>
    <system.web>
        <authentication    mode="Forms">
            <forms name="MYWEBAPP.ASPXAUTH"
                loginUrl="login.aspx"
                protection="All"
                path="/"/>
        </authentication>
        <authorization>
            <allow users="*"/>
        </authorization>
    </system.web>
</configuration>

The FormsAuthentication name (MYWEBAPP.ASPXAUTH) above it arbitrary, although the name there and the name in the HttpCookie we created to hold the hashed FormsAuthenticationTicket must match, for even though we are overriding the ticket creation, ASP.NET still handles the authorization automatically from the Web.config file.

To control authorization (access by a particular user or group), we can either 1) add some more elements to the Web.config file from above, or 2) create a separate Web.config file in the directory to be secure. While, I prefer the second, I will show the first method:

<configuration>
    <system.web>
        <authentication mode="Forms">
            <forms name="MYWEBAPP.ASPXAUTH"
                loginUrl="login.aspx"
                protection="All"
                path="/"/>
        </authentication>
        <authorization>
            <allow users="*"/>
        </authorization>
    </system.web>
    <location path="administrators">
        <system.web>
            <authorization>
                <!-- Order and case are important below -->
                <allow roles="Administrator"/>
                <deny users="*"/>
            </authorization>
        </system.web>
    </location>
    <location path="users">
        <system.web>
            <authorization>
                <!-- Order and case are important below -->
                <allow roles="User"/>
                <deny users="*"/>
            </authorization>
        </system.web>
    </location>
</configuration>

The Web Application always creates relative paths from the paths entered here (even for login.aspx), using it's root directory as the starting point. To avoid confusion with that condition and to make directories more modular (being able to move them around without changing a bunch of files), I choose to put a separate Web.config file in each secure sub-directory, which is simply the <authorization/> section like so:

<configuration>
    <system.web>
        <authorization>
            <!-- Order and case are important below -->
            <allow roles="Administrator"/>
            <deny users="*"/>
        </authorization>
    </system.web>
</configuration>

Notice, too, that the role(s) is/are case-sensitive. If you want to allow or deny access to more than one role, delimit them by commas.

That's it! Your site is setup for role-based security. If you use code-behind, compile your application first. Then try to access a secure directory, such as /administrators, and you'll get redirected to the login page. If login was successful, you're in, unless your role prohibits it, such as the /administrators area. This is hard for the login.aspx page to determine, so I'd recommend a Session variable to store the login attempts and after so many times, return an explicit "Denied" statement. There is another way, however, which is discussed below.

Conditionally Showing Controls with Role-based Forms Authentication

Sometimes it's better to show / hide content based on roles when you don't want to duplicate a bunch of pages for various roles (user groups). Such examples would be a portal site, where free- and membership-based accounts exist and membership-based accounts can access premium content. Another example would be a news page that would display an "Add" button for adding news links if the current user is in the "Administrator" role. This section describes how write for such scenarios.

The IPrincipal interface, which the GenericPrincipal class we used above implements, has a method called IsInRole(), which takes a string designating the role to check for. So, if we only want to display content if the currently logged-on user is in the "Administrator" role, our page would look something like this:

<html>
<head>
  <title>Welcome</title>
  <script runat="server">
  protected void Page_Load(Object sender, EventArgs e)
  {
   if (User.IsInRole("Administrator"))
    AdminLink.Visible = true;
  }
  </script>
</head>
<body>
  <h2>Welcome</h2>
  <p>Welcome, anonymous user, to our web site.</p>
  <asp:HyperLink id="AdminLink" runat="server"
   Text="Administrators, click here." NavigateUrl="administrators/"/>
</body>
</html>

Now the link to the Administrators area of the web site will only show up if the current user is logged in and is in the "Administrator" role. If this is a public page, you should provide a link to the login page, optionally setting the QueryString variable called ReturnUrl to the path on the server you want the user to return to upon successful authentication.

Summary

This tutorial was created to help you understand the important of role-based security, as well as implement role-based security on your web site with ASP.NET. It's not a hard mechanism to implement, but it does require some know-how of what principals are, how credentials are authenticated, and how users / roles are authorized. I hope you have found this tutorial helpful and interesting, and that it leads you to implement role-based Forms Authentication on your current or upcoming site!

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
General...
dooglex
8:44 27 Jan '10  
thank youu Smile) Sniff


GeneralThanks
Anuj Tripathi
5:51 7 Jan '10  
Hi Heath,

This article is really helpful as well as simpler to understand & implement.
Can you please provide the same type of article for passport authentication & autherzation.
Thanks in advance !
GeneralRe: Thanks
Heath Stewart
9:49 30 Jan '10  
There's already some good articles about this at http://msdn.microsoft.com/en-us/library/f8e50t0f(VS.71).aspx[^], http://msdn.microsoft.com/en-us/library/f8e50t0f(VS.80).aspx[^], and http://msdn.microsoft.com/en-us/library/aa530793.aspx[^]. The latter is for 2.0 and newer, but I highly recommend ASP.NET 2.0 or newer over any 1.x solution.

This posting is provided "AS IS" with no warranties, and confers no rights.

Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft

[My Articles] [My Blog]

QuestionApplication_AuthenticateRequest, unable to test project on Visual Studio 2010 Beta 2
john_1726
13:57 7 Dec '09  
Please note that I have been unable to get your sample working on VS 2010 beta 2. In particular, when I create/add the Global.asax file, I cannot see there any method called Application_AuthenticateRequest(...), or anywhere else in the solution for that matter. Do you have any suggestions? The Application_AuthenticateRequest is generated by VS, is it not?

TIA.
GeneralCS0029 Error. How can I fix it? I am really a newbie on this. Please help
eggy168
11:50 23 Jul '09  
Hi,
I got an error message, CS0029 cannot implicitly convert type "string" to system.web.ui.webcontrols.labels after I copy and paste all the code into a new asp.net page. I just don't know how to fix it and now I am stuck on it. can anyone help me to solve it since I am just started learning how to write asp.net.
Thank you very much.
GeneralRe: CS0029 Error. How can I fix it? I am really a newbie on this. Please help
Heath Stewart
6:13 26 Jul '09  
On whatever line number the error mentions, add ".Text" to the label where the string is assigned.

But you shouldn't even be using this anymore. This predates ASP.NET 2.0 that added support for more advanced role membership, built around a whole framework of abstraction.

This posting is provided "AS IS" with no warranties, and confers no rights.

Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft

[My Articles] [My Blog]

GeneralMachine Key
Lonj
9:43 13 Apr '09  
I had this working in a one-server environment, but when moved to server farm, it keeps redirecting back to the log in. The best I can determine is that it is using the machine key to encrypt and when it want to authenticate, is hitting a different server in the farm and fails. What is the solution to this in a server farm?

// Encrypt the cookie using the machine key for secure transport

string hash = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(
FormsAuthentication.FormsCookieName, // Name of auth cookie

hash); // Hashed ticket

thank you in advance...
GeneralRe: Machine Key
Heath Stewart
9:51 30 Jan '10  
You need to edit your site's web.config (or even machine's machine.config (.NET 1.x) or default web.config (.NET 2.0+)) to specify the same key across a farm. See http://msdn.microsoft.com/en-us/library/ms998288.aspx#paght000007_webfarmdeploymentconsiderations[^].

This posting is provided "AS IS" with no warranties, and confers no rights.

Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft

[My Articles] [My Blog]

GeneralNot Working
marwan1984
1:04 12 Apr '09  
I thinks we should replace redirect by RedirectFromLoginPage Method????
GeneralThank you
One Excluded
9:32 24 Feb '09  
really....Thumbs Up
GeneralApplication_AuthenticateRequest never get HttpContext.Current.User
belfegor
7:32 24 Feb '09  
Hi...very good article

There's somebody can help me???...Need some guidance with this problem...(asp.net 2.0/vstudio 2005)

I have the next directory structure

/root
web.config
default.aspx
/admin
      workspace.aspx
/user
      workspace.aspx

and web.config see like this:

      <pre>
<!--<authentication mode="Windows"/> -->
      <authentication mode="Forms">
         <forms loginUrl="default.aspx" defaultUrl="user/workspace.aspx" name="ck.SRCI.ESEPEAuth" timeout="30" path="/" protection="All" slidingExpiration="true">
         </forms>
      </authentication>
      <authorization>
         <!--<deny users="?" />-->
         <allow users="*"/>
      </authorization>
</system.web>
<location path="user">
      <system.web>
         <authorization>
            <allow roles="Usuario"/>
            <deny users="*"/>
         </authorization>
      </system.web>
   </location>
   <location path="admin">
      <system.web>
         <authorization>
            <allow roles="Administración"/>
            <deny users="*"/>
         </authorization>
      </system.web>
   </location>
</pre>


I can validate correctly user access on default.aspx :

   <pre>FormsAuthentication.Initialize();

                  string roles = BLL.Permisos.Instance.getUsuarioRoles(SessionManager.Instance.currentUserId);

                  if (BG.Tools.Configuration.Instance.isSuperAdmin(SessionManager.Instance.currentUserId))
                  {
                        if (roles != "")
                        {
                              roles += "|sadmin";
                        }
                        else
                        {
                              roles += "sadmin";
                        }

                  }

                  FormsAuthenticationTicket oTicket = new FormsAuthenticationTicket(
                        1,
                        SessionManager.Instance.currentUser,
                        DateTime.Now,
                        DateTime.Now.AddMinutes(SessionManager.Instance.sessionTimeout),
                        false,
                        roles,
                        FormsAuthentication.FormsCookiePath);

                  string encryptedTicket = FormsAuthentication.Encrypt(oTicket);


                  HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
                  if (oTicket.IsPersistent) authCookie.Expires = oTicket.Expiration;
                  Response.Cookies.Add(authCookie);

                  Response.Redirect("user/workspace.aspx",false);</pre>

And redirect to default users page, but on global.asax y receive always HttpContext.Current.User==null and cannot create the IPrincipal object


<pre>protected void Application_AuthenticateRequest(object sender, EventArgs e)
      {
            <b>if (HttpContext.Current.User != null)</b>            {

                  if (HttpContext.Current.User.Identity.IsAuthenticated)
                  {

                        if (HttpContext.Current.User.Identity is FormsIdentity)
                        {
                              FormsIdentity id = (FormsIdentity)HttpContext.Current.User.Identity;
                              FormsAuthenticationTicket ticket = id.Ticket;

                              // Get the stored user-data, in this case, our roles
                              string userData = ticket.UserData;
                              string[] roles = userData.Split('|');
                              HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(id, roles);
                        }
                        else
                        {
                              Response.StatusCode = 401;
                              throw new Exception("Método de autentificación no soportado " +
                                    HttpContext.Current.User.Identity.AuthenticationType);
                        }
                  }
            }
}</pre>

What I'm doing wrong (cookies are already sent but always I'm redirected to the login page)???

Previously I made correct forms/windows mixed authentication with custom roles but I can't understand this new 'dilema'

Thanks in advice
AnswerRe: Application_AuthenticateRequest never get HttpContext.Current.User
belfegor
13:43 24 Feb '09  
now...I answer my self (too many time wasted and I forget to think about it more harder)

"there is a limit of 4KB that is dictated by the max cookie size"

I was putting many privilegies on the ticket userdata

The solution was to move the roles string info on aditional crypted cookie and now all is working like a charm!!!
QuestionAlways show incorrect user name
Himanshu Verma
1:03 30 Dec '08  
Hi,
I have implemented your coding as it but whenever I login it shows incorrect login/password. I dont know why it bypass the if block and comes directly in else block of login page's btnclick event.
Also I am confused of using name property in <Form> tag, what should be name property for me.
GeneralRoleManager and RoleProvider
an_phu
8:43 24 Dec '08  
People should really be using the RoleManager and RoleProvider now. They were part of the ASP.NET 2.0 release.
QuestionProblem with login
Proteus
0:04 22 Oct '08  
Hi,
I have implement this solution in my application. When I login to system for the first time, everything works great. But when I logout , and want to login once again there appear page with this message HTTP Error 404 - Not Found. If I want to login to system after this error shows, I have to go back to previous page (login page), reload it, and then my user is login to system.
Can someone help me?
GeneralWroked like charm!
rawwool
1:40 19 Oct '08  
I changed the storage to XML and used XPath query instead.
GeneralRedirectFromLoginPage method of forms authentication failed to redirect to originally requested page
PranjaliBhide
0:05 30 Sep '08  
I developed a site with a reserved section based on roles, when I try to access that page i got redirected correctly to the loginpage and on the address bar i see
the ReturnUrl containig the address to point to:

http://localhost/SiteName/login.aspx?ReturnUrl=%2fSiteName%
2fadministrator%2fdefault.aspx

administrator/default.aspx is the page I have to reach
I authenticate succesfully but when the following instruction executes without error:
FormsAuthentication.RedirectFromLoginPage(user, chkRemember.Checked)
i still remain in the same page, only user and pwd disappear

the address in the bar is still the same....

otherwise if i submit incorrect user o pwd I got an error that indicates the redirect correctly fails:
If AuthenticateUser(userEncoded, pwdEncoded, roles) Then
FormsAuthentication.RedirectFromLoginPage("@" & ruoli, chkRemember.Checked)

Else
lblLogin.Text = "Access denied!"
End If


Any idea?

Thanks,
In Advance.
Generalvery helpful one thanks
snopbear
0:34 28 Aug '08  
very helpful one thanks Shucks
GeneralCan't Sign Out a user whatsoever.
johnnythaiho
5:47 22 Aug '08  
Hi,

I used your tutorial and log user in successfully with their roles, but I have problem to sign out the user. After sign out, the user still be able to go back to the security page without log in. I think it's the problem with cashing memory. I google around any use all suggestion but it doesn't work at all. I hope you can help me out here.

FYI: I used all the code as suggest as below:
FormsAuthencation.SignOut();
Session.Abondon();
HttpCookie cookies = Context.Request.Cookies[FormsAuthentication.FormsCookieName];//Or Response
cookies.Expires = DateTime.Now.AddDays(-1);
Context.Response.Cookies.Add(cookies);

Thanks in advance.

Johnny
GeneralRe: Can't Sign Out a user whatsoever.
Member 1525121
7:33 27 Aug '08  
Hi,

I also cannot sign out at all... this worked fine in 1.1, but trying in 3.5 now (2.0) and it simply doesn't log the user out.

Have tried removing the cookie, setting the current user to null, SignOut(), RedirectToLoginPage(), all sorts.

Does anyone have any ideas how to sign out of a custom role-based forms authentication???

Cheers,

Tom.
GeneralRe: Can't Sign Out a user whatsoever.
johnnythaiho
8:18 27 Aug '08  
Hi Tom,

FormsAuthentication.SignOut() will sign out the user, but won't clear the cache memory.

Try to find out yourself by sign the user out with FormAuthentication.SignOut() and get back to that page with the url address. It will let you in, but if you hit the refresh button, it will kick you out of that page and forward you to the Login.aspx page (if you set up that way).

If this is the issue, don't try to waist your time with some suggestions like to set the cookies.Expire because this has nothing to do with cookies.

Here is what I found and it work for me.

you can use the directive for your page like this
<![CDATA[<% OutputCache Duration="1" VaryByParm="none" %>]]>

or set the cache expire with Page_Load for that page, I like this way better

protected void Page_Load(object sender, EventArgs e)
{
Response.Cache.SetExpries(DateTime.Now);
}

Good Luck,

Johnny
GeneralRe: Can't Sign Out a user whatsoever.
Member 1525121
23:03 27 Aug '08  
Thanks for your prompt reply, Johhny.

Unfortunately, this also did not work for me - I had tested whether it might be the cache. Refreshing the page doesn't redirect me to the login, so I can only assume that the cache is not the issue.

This is really quite a puzzler - as I mentioned, this all seemed to work fine in ASP.NET 1.1.

Here is my code, in case you have any other suggestions:

Login.aspx button_click event


// check that the user's password hash and username are present
// get the user's roles from the DB

// set up the authentication:

// create an authentication ticket
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1, // version
TextEmail.Text, // user name
DateTime.Now, // creation
RememberLogin.Checked ? DateTime.MaxValue : DateTime.Now.AddMinutes(120),// expiration
RememberLogin.Checked, // persistent
roles // user data
);

// encrypt the ticket
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);

// create a cookie and add the encrypted ticket to the cookie as data
// this cookie is used in the global AuthenticateRequest event to
// retreive the userid and then get the user from the system and store
// the data in the context for the remainder of the request
HttpCookie authCookie = new HttpCookie(
FormsAuthentication.FormsCookieName,
encryptedTicket);

// if the user has asked us to remember them, then we want the cookie to last for ever
if (authTicket.IsPersistent)
authCookie.Expires = authTicket.Expiration;
else
authCookie.Expires = DateTime.Now.AddMinutes(120);

// add the cookie to the outgoing cookies collection
Response.Cookies.Add(authCookie);

// this cookie as we already have in the code above
if (FormsAuthentication.GetRedirectUrl(TextEmail.Text, false).Length > 0)
{
string rdUrl = FormsAuthentication.GetRedirectUrl(TextEmail.Text, false);
Response.Redirect(FormsAuthentication.GetRedirectUrl(TextEmail.Text, false));
}
else Response.Redirect("default.aspx");


Global.asax

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;

// Get the stored user-data, in this case, our roles
string userData = ticket.UserData;
string[] roles = userData.Split(',');
HttpContext.Current.User = new GenericPrincipal(id, roles);
}
}
}
}


Any ideas you may have would be appreciated.

Many thanks in advance,

Tom.
GeneralRe: Can't Sign Out a user whatsoever.
Tommy W
23:35 27 Aug '08  
Hi Johnny, Heath, All,

I am still slightly confused, but have found a solution to this issue.

I was attempting to set the name and domain of the name and domain of the cookie:

    <authentication mode="Forms">
<forms loginUrl="~/login.aspx"
domain="www.somesite.com"
name="somesite">
</forms>
</authentication>


However, as I was running on localhost:xxx I assume that this caused the issue. Perhaps when the application is actually sitting on the domain, this will be fine.

Thanks very much for your help!

Tom.
GeneralRe: Can't Sign Out a user whatsoever.
johnnythaiho
4:08 28 Aug '08  
Hi Tom,

I am glad that you found the solution. I am sure that your input above will help other people. Also I like to say thanks to Mr. Stewart for his very usefull article.

Johnny.
GeneralRe: Can't Sign Out a user whatsoever.
Tommy W
4:10 28 Aug '08  
As would I!


Last Updated 26 Jul 2009 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010