Forms Authentication in ASP.NET 2.0

P

Peter Bradley

We are in the process of designing our first ASP.NET 2.0 application and
have discovered that Forms Authentication works completely differently in
ASP.NET 2.0.

For a number of reasons, we cannot use the standard login component supplied
with ASP.NET 2.0 (e.g. we need full control of the look and feel - including
using CSS and not tables for layout - and we need to be able to handle the
authentication cookie ourselves rather than let a built-in component handle
it for us). We also need to use the Application_Start event to read lookup
data from our databases.

Does anyone know how to get back to something like the .NET 1.1 model for
coding forms authentication.

I'm not dead against using the supplied components, BTW, as long as we get
the functionality we had before and as long as we can style the visible
components ourselves.



Peter
 
G

Guest

Peter Bradley said:
We are in the process of designing our first ASP.NET 2.0 application and
have discovered that Forms Authentication works completely differently in
ASP.NET 2.0.

For a number of reasons, we cannot use the standard login component
supplied with ASP.NET 2.0 (e.g. we need full control of the look and
feel - including using CSS and not tables for layout - and we need to be
able to handle the authentication cookie ourselves rather than let a
built-in component handle it for us). We also need to use the
Application_Start event to read lookup data from our databases.

Does anyone know how to get back to something like the .NET 1.1 model for
coding forms authentication.

I'm not dead against using the supplied components, BTW, as long as we get
the functionality we had before and as long as we can style the visible
components ourselves.

Hi Peter

design you own login.aspx page

On submit event add the following code

------------------------------
if UserName and Password were correct

// Initialize FormsAuthentication
FormsAuthentication.Initialize();

// Create a new ticket used for authentication
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
UserName, // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMonths(1), // Date/time to expire
true, // "true" for a persistent user cookie
UserRoles, // 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 homepage
Response.Redirect("/");
 
P

Peter Bradley

Anon User said:
Hi Peter

design you own login.aspx page

On submit event add the following code

------------------------------
if UserName and Password were correct

// Initialize FormsAuthentication
FormsAuthentication.Initialize();

// Create a new ticket used for authentication
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
UserName, // Username associated with ticket
DateTime.Now, // Date/time issued
DateTime.Now.AddMonths(1), // Date/time to expire
true, // "true" for a persistent user cookie
UserRoles, // 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 homepage
Response.Redirect("/");

Hi Alexey,

Thanks for that. This is pretty much what we do now as far as the login
page is concerned. We then add attributes to the classes and methods to
which we wish to restrict access, specifying that the user must be logged in
and a member of the appropriate role in order to execute the code in that
method or access an object of that class (depending on requirements). This
causes an authentication request event to be raised, which is handled in
Global.asax.cs in the Application_AuthenticateRequest() event handler. This
handler fetches the authentication cookie and creates a
FormsAuthenticationTicket to which is assigned the decrypted cookie value.

We then extract the user's roles from that and create a new GenericIdentity
passing in the FormsAuthenticationTicket. Finally, we create a new
GenericPrincipal object passing in the GenericIdentity and the roles.

Lastly, we assign the GenericPrincipal to the user in the current context.

My question, really, is where do we now put this code? Where are
AuthenticateRequest events handled?


Peter
 
G

Guest

Peter Bradley said:
My question, really, is where do we now put this code? Where are
AuthenticateRequest events handled?

The authentication ticket has to be created right after the login info is
confirmed. Because the ticket is used to identify an authenticated user. So,
it can be in the login page, which is defined in the Authentication section
in web.config

<authentication mode="Forms">
<forms name=".ASPXAUTH" loginUrl="/login.aspx" />
</authentication>

I've found an example of a role-based authentication, take a look
http://www.codeproject.com/aspnet/formsroleauth.asp

Cheers!
 
P

Peter Bradley

I don't think you're understanding where I'm coming from, Alexey.

We already use forms authentication and role-based security using .NET 1.1,
using the technique outlined in the article you refer to, which says:

"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:"

The problem is that in .NET 2.0 there no longer appears to be a
Global.asax.cs file and no handler for the AuthenticatRequest event.

What I need to know is what modifications I have to make to my .NET 1.1 code
to make it work in .NET 2.0. Where do I put the code that, in .NET 1.1,
used to go in the Application_AuthenticateRequest handler, which appears no
longer to have a home?

Cheers



Peter
 
G

Guest

The problem is that in .NET 2.0 there no longer appears to be a
Global.asax.cs file and no handler for the AuthenticatRequest event.

I'm really trying to understand the problem :)

Open the project in VS 2005

A new global.asax can be added using Add - Add New Item - Global
Application Class. If you have one already, delete it and add again,
maybe this is your problem and this is what I don't get.

Once it's added, you will see the Global.asax and Global.asax.cs in
the Solution Explorer.

If you don't see the code-behind file, right click on Global.asax,
View Markup

You should have something like this

<%@ Application Codebehind="Global.asax.cs"
Inherits="WebApplication1.Global" Language="C#" %>

the code behind Global.asax.cs will have Application_Start() and
Application_End() by default, I think. You just need to add the
Application_AuthenticateRequest() to make it working with roles.

Global.asax.cs:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Security.Principal;

namespace ........
{
public class Global : System.Web.HttpApplication
{

protected void Application_Start(object sender, EventArgs e)
{

}

protected void Application_End(object sender, EventArgs e)
{
}

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);
}
}
}
}
}
}

Does it answer the question?
 
P

Peter Bradley

Nope. In VS2005 you can add a Global.asax file, because there isn't one by
default when you add a new Web Site; but there is no code behind page and no
way that I can see of creating one.

Sorry if I sounded a bit short before, by the way, it was not intentional.
I'm very grateful for your interest.


Peter

Anon User said:
The problem is that in .NET 2.0 there no longer appears to be a
Global.asax.cs file and no handler for the AuthenticatRequest event.

I'm really trying to understand the problem :)

Open the project in VS 2005

A new global.asax can be added using Add - Add New Item - Global
Application Class. If you have one already, delete it and add again,
maybe this is your problem and this is what I don't get.

Once it's added, you will see the Global.asax and Global.asax.cs in
the Solution Explorer.

If you don't see the code-behind file, right click on Global.asax,
View Markup

You should have something like this

<%@ Application Codebehind="Global.asax.cs"
Inherits="WebApplication1.Global" Language="C#" %>

the code behind Global.asax.cs will have Application_Start() and
Application_End() by default, I think. You just need to add the
Application_AuthenticateRequest() to make it working with roles.

Global.asax.cs:

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Security.Principal;

namespace ........
{
public class Global : System.Web.HttpApplication
{

protected void Application_Start(object sender, EventArgs e)
{

}

protected void Application_End(object sender, EventArgs e)
{
}

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);
}
}
}
}
}
}

Does it answer the question?
 
G

Guest

Peter Bradley said:
Nope. In VS2005 you can add a Global.asax file, because there isn't one
by default when you add a new Web Site; but there is no code behind page
and no way that I can see of creating one.

I was talking about a Web applications. The Web application is a new project
type in VS 2005. Web sites differ from Web applications.

I've created a new Web site project to see how it handles with a global.asax
and here's what I have found so far:

1. Global.asax cannot be created with the code-behind file. Option to Place
code in separate file is disabled.

2. Global.asax uses a code-inline model

<%@ Application Language="C#" %>

<script runat="server">

void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup

}

void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown

}

void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs

}

void Session_Start(object sender, EventArgs e)
{
// Code that runs when a new session is started

}

void Session_End(object sender, EventArgs e)
{
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to
StateServer
// or SQLServer, the event is not raised.

}

</script>

By default it has no Application_AuthenticateRequest.

To create it use the dropdowns above the code window. In the Object list (at
right) select the Application, then in the Event list select
AuthenticateRequest. It will add a new event as following

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{

}

3. If you want to use code-behind, delete all the code from Global.asax and
change the Page directive

<%@ Application Codebehind="Global.asax.cs"
Inherits="WebApplication1.Global" Language="C#" %>

Then add a new class file named Global.asax.cs into the App_Code and copy
the code I have sent you yesterday

public class Global : System.Web.HttpApplication
{
.....
}
 
P

Peter Bradley

By default it has no Application_AuthenticateRequest.

To create it use the dropdowns above the code window. In the Object list
(at right) select the Application, then in the Event list select
AuthenticateRequest. It will add a new event as following

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{

}

Tremendous, Alexey. Thanks.

Why do these things always get put in the one place I haven't looked?

:)
3. If you want to use code-behind, delete all the code from Global.asax
and change the Page directive

Nope. We're happy with the inline way.

Many thanks again. Someone should put this on a blog somewhere (hint,
hint).



Peter
 
G

Guest

Tremendous, Alexey. Thanks.

Why do these things always get put in the one place I haven't looked?

:)


Nope. We're happy with the inline way.

Many thanks again. Someone should put this on a blog somewhere (hint,
hint).

Peter

Peter, glad you got that working!
 
P

Peter Bradley

Ysgrifennodd Anon User:
Peter, glad you got that working!

I've updated our documentation and created a small example application.
Perhaps I'll put it up on a Web site somewhere.


Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,060
Latest member
BuyKetozenseACV

Latest Threads

Top