Click to See Complete Forum and Search --> : ASP.NET role-based login. Problem using RedirectFromLoginPage.


Anton Margo
September 8th, 2004, 05:12 PM
Dear Professionals, I need your help because I am stuck.

I am trying to implement a role based ASP.NET authentication model with a single login page. I have several account types which should be redirected to a unique main page (for each account). Where if user is admin he will put his username and password and he should be verified and redirected to the adminmain.aspx, if other type then redirect should be othertypemain.aspx.

I am using the article
http://aspnet.4guysfromrolla.com/articles/082703-1.2.aspx
to implement the asp form authentication, and asp.net redirectfromlogin method to automatically create a session for any user who already logged in.


My login button has code:


Sub Submit_OnClick(sender as Object, e as EventArgs)
If Authenticate (txtUserName.Text, txtPassword.Text) Then

'Determine this user's status
Dim type as String = Getusertype(txtUserName.Text, txtPassword.Text)

Dim roleList As New ArrayList
roleList.Add("type")
Dim roleListArray As String() = roleList.ToArray(GetType(String))

HttpContext.Current.User = _
New System.Security.Principal.GenericPrincipal(User.Identity, roleListArray)

FormsAuthentication.RedirectFromLoginPage (txtUserName.Text, True)
Else
' Invalid credentials supplied, display message
Response.Write ("Invalid login credentials")
End If
End Sub


Function Authenticate checks if username and pwd are valid.
Function Getusertype checks the database and returns a string with account type.
Then each page will check if the user belongs to a certain group or not:


If User.IsInRole("Administrator") then
' Display sensitive material
End If


PROBLEM :
1)
Since I am using ASP.NET form authentication, I can not set the specific redirect page based on the type of the user account that i get from function Getusertype. *

FormsAuthentication.RedirectFromLoginPage (txtUserName.Text, True)
- this only takes username.

And I would want the code to create a session and redirect to the page I need (based on the account type). This way i will simple use code below to check if the user can see the xxxmain.aspx or not.

If User.IsInRole("xxx") then
' Display sensitive material
End If


*I believe there is a way to select a redirect page for RedirectFromLoginPage method by setting returnURL in the URL string, however I dont really want to post back to a login page and then redirect. Is there any nicer way?

2) I hope I am creating a role correctly:

'Determine this user's status
Dim type as String = getusertype(txtUserName.Text, txtPassword.Text)

Dim roleList As New ArrayList
roleList.Add("Admin")
Dim roleListArray As String() = roleList.ToArray(GetType(String))

HttpContext.Current.User = _
New System.Security.Principal.GenericPrincipal(User.Identity, roleListArray)

Please let me know if I am missing something.


Thanks a lot for all the useful comments,
I appreciate any help or links on the matter.
A.M.

MRutledge
September 8th, 2004, 05:50 PM
In regards to your redirect problem. You do not have to use the redirect from login page function. Instead you can set the Forms authentication cookie by calling
FormsAuthentication.SetAuthCookie method and then you can determine what role the user is in by using the User.Identity.IsInRole method to redirect them to a specific page. i.e.


FormsAuthentication.SetAuthCookie(sLogin, false);

if(User.Identity.IsInRole("admin"))
{
Response.Redirect("adminpage.aspx");
}


As far as creating the roles it looks right to me, but I do not know for sure.

Anton Margo
September 8th, 2004, 07:50 PM
Good point. I v been able to see authentication inside the login page.
(I can see "ADMIN U ARE GOOD!", from code below)


Dim roleListArray As String() = roleList.ToArray(GetType(String))
Dim fID As New System.Security.Principal.GenericIdentity(strUsername)
HttpContext.Current.User = New System.Security.Principal.GenericPrincipal(fID,roleListArray)

FormsAuthentication.SetAuthCookie(strUsername,True)

If HttpContext.Current.User.IsInRole("Admin") then
Response.Write ("ADMIN U ARE GOOD")
End If

response.redirect(redirectUrl)


However once I do


IF User.IsInRole("Admin") THEN
Response.Redirect("adminmain.aspx")
END IF


Then the next page does not keep the session. This returns blank for this code:

FormsAuthentication.Initialize()
Response.Write( "Authenticated Identity is: " & HttpContext.Current.User.Identity.Name )


So somehow the next page is unable redirect while keeping the Current.User identity. I though it would because of the SetAuthCookie method. How do I keep User identity for all the pages then?

MRutledge
September 8th, 2004, 09:49 PM
Make sure you have set the web.config file properly
Something like this:

<configuration>
<system.web>
<authentication mode="Forms">
<forms name=".COOKIEDEMO"
loginUrl="login.aspx"
protection="All"
timeout="30"
path="/"/>
</authentication>
<authorization>
<deny users="?" />
</authorization>
</system.web>
</configuration>


Also see when you get to the next page see if you can get the auth cookie by using the FormsAuthentication.GetAuthCookie method. The reason I say this is that something may be blocking the cookie from being set.

Anton Margo
September 9th, 2004, 12:18 PM
Thanks, Matt. I have correctly setup my web.config and can see a cookie saved on my machine.

I have noticed an interesting defect with SetAuthCookie(username, true) - it fails to set a correct expiry date so i have to change it myself by using GetAuthCookie(username, true) and manually setting expiry date to dateadd("d",1,DateTime.Now). Then I write the cookie into Reponse.Write and only then I can see that cookie on the next page.

So far so good, but I am still failing to see a correct role on the other page (redirected to by login.aspx). On login page I can set the role to the Current.User and then view it with the User.IsInRole Function:


If HttpContext.Current.User.IsInRole("Admin") then
' Display sensitive material
Response.Write ("ADMIN U ARE GOOD")
Else
' Display only bland material
Response.Write ("GET OUT!")
End If


I can see ADMIN U ARE GOOD perfectly on login.aspx, but never on the next page. Maybe I need to save Current.User somehow? Write it in a cookie or something? So far I only write username in a cookie which I do not see how it refers to Current.USer object which I add all the roles to.

The page I redirect to from login fails to get the Amin role I set up on the login:
This is the code I use for login to set the role. The way i check for a role on the redirected page is same as above.


Dim roleList As New ArrayList
roleList.Add("Admin")

'Convert the roleList ArrayList to a String array
Dim roleListArray As String() = roleList.ToArray(GetType(String))

Dim fID As New System.Security.Principal.GenericIdentity(strUsername)
HttpContext.Current.User = New System.Security.Principal.GenericPrincipal(fID,roleListArray)
FormsAuthentication.SetAuthCookie(HttpContext.Current.User.Identity.Name,true)
Dim cookie As System.Web.HttpCookie = FormsAuthentication.GetAuthCookie(strUsername,true)

cookie.Expires = Dateadd("d",1,DateTime.Now)
Response.Write(cookie)
Response.Redirect("adminmain.aspx")

MRutledge
September 9th, 2004, 12:21 PM
YOu have to remember to set the roles of the context on each http request. I would check to see if the context has been set and then set the roles if it hasnt been set. This would be good to put in the global.asax file in the Authenticate_Request method.

Anton Margo
September 9th, 2004, 01:28 PM
So basically you are saying that I have to set the roles on every page that Authenticated user accesses? Because this way it looks very much redundant, since it would hit database a lot.

Code @ global.asax would be like :

Sub Application_AuthenticateRequest(sender As Object, e As EventArgs)
If Request.IsAuthenticated Then
' Create an array of role names
roleList.Add("Admin")

'Convert the roleList ArrayList to a String array
Dim roleListArray As String() = roleList.ToArray(GetType(String))

'Add the roles to the User Principal
HttpContext.Current.User = _
New GenericPrincipal(User.Identity, roleListArray)
End If
End Sub


Maybe it would be more reasonable to have a session cookie with account type? I clearly doubt the efficiency of the role based approach unless it somehow saves the role so it wouldnt have to hit DB for every new page authenticated user has access to.

Thanks for all the help.

MRutledge
September 9th, 2004, 01:32 PM
I dont know if that is the way it works. I thought it did store the roles in the auth cookie. I just suggested something to see if it is resetting the values. You are almost there though.