rgrimm
asked on
ASP.NET: User.Identity.Name and User.IsInRole() not getting populated the first time
I am using Forms authentication for my web site. My login page gets the user's login and password.
I look it up in a database, and if everything is OK, then I go ahead and create an authentication
ticket and put it into the cookie (see CODE A below). I then transfer to the main page for the site.
The main page does the Page_Load event code (see CODE B below). If I put a breakpoint at the end of
it and use the Debug window to see what the User.Identity.Name is, and see if the User.IsInRole() is
set, I find that both of them are empty. So it seems like I am failing to get this information into
the ticket (which then populates the IPrincipal info).
So what am I doing wrong? I do know that I got the data out of the database OK, because I stuff
some of it into session variables and it is there (Session("FName"), for example). It just isn't getting
into the httpContext.Current.User object.
(One more bit of information. If I where to hit Shift+F5 and end the session,
and then hit F5 to restart it, then everything will be OK. However, if I logout, then I am back to
my broken state.)
CODE A --- CODE A --- CODE A --- CODE A
Dim cookie As HttpCookie
Dim strHash As String
Dim strTransferTo As String = "Users/SiteNav.aspx"
'Create a new forms authentication ticket used with the user's information
'version = 1
'name = login name (tbLogin.Text)
'issueDate = Now
'Expiration Date = Now + Session timeout minutes
'IsPersistent = TRUE
'userData = user's roles in a comma-delimited list
'cookiepath - not used. MCD is cookieless
Dim ticket As New FormsAuthenticationTicket( 1, _
tbLogin.Text, _
Now, _
Now.AddMinutes(Session.Tim eout), _
True, _
UserInfo.RoleNames) ', _
'FormsAuthentication.Forms CookiePath )
'Encrypt the ticket and put it into the cookie
strHash = FormsAuthentication.Encryp t(ticket)
cookie = New HttpCookie(FormsAuthentica tion.Forms CookieName , strHash)
'Set the cookie's expiration time to the ticket's expiration time
If ticket.IsPersistent Then
cookie.Expires = ticket.Expiration
'Add the cookie to the list for outgoing response
Response.Cookies.Add(cooki e)
End If
Server.Transfer(strTransfe rTo)
END CODE A --- END CODE A --- END CODE A --- END CODE A
CODE B --- CODE B --- CODE B --- CODE B --- CODE B
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Session Variables Available: EID, Login, LoginID, FName, LName
'Reset the session timeout
If Not Page.IsPostBack Then
Response.AppendHeader("Ref resh", Convert.ToString((Session. Timeout * 60) + 10) & "; url=http://www.mychurchdata.com/Login.aspx")
ifContent.Attributes.Add(" Src", "Users/Main.aspx?Return=Po stback")
'Set Login Name
lblLogin.Text = " " + Session("FName") + " " + Session("LName") + " is logged in."
'If no current user, then return to default page.
If Session("Login") = "" Then
Response.Redirect("../defa ult.aspx")
Exit Sub
End If
'Set menu visibility
pnlMainMenu.Visible = True
If User.IsInRole("Administrat or") = True Then pnlAdminMenu.Visible = True 'SET BREAKPOINT HERE
END CODE B --- END CODE B --- END CODE B --- END CODE B --- END CODE B
I look it up in a database, and if everything is OK, then I go ahead and create an authentication
ticket and put it into the cookie (see CODE A below). I then transfer to the main page for the site.
The main page does the Page_Load event code (see CODE B below). If I put a breakpoint at the end of
it and use the Debug window to see what the User.Identity.Name is, and see if the User.IsInRole() is
set, I find that both of them are empty. So it seems like I am failing to get this information into
the ticket (which then populates the IPrincipal info).
So what am I doing wrong? I do know that I got the data out of the database OK, because I stuff
some of it into session variables and it is there (Session("FName"), for example). It just isn't getting
into the httpContext.Current.User object.
(One more bit of information. If I where to hit Shift+F5 and end the session,
and then hit F5 to restart it, then everything will be OK. However, if I logout, then I am back to
my broken state.)
CODE A --- CODE A --- CODE A --- CODE A
Dim cookie As HttpCookie
Dim strHash As String
Dim strTransferTo As String = "Users/SiteNav.aspx"
'Create a new forms authentication ticket used with the user's information
'version = 1
'name = login name (tbLogin.Text)
'issueDate = Now
'Expiration Date = Now + Session timeout minutes
'IsPersistent = TRUE
'userData = user's roles in a comma-delimited list
'cookiepath - not used. MCD is cookieless
Dim ticket As New FormsAuthenticationTicket(
tbLogin.Text, _
Now, _
Now.AddMinutes(Session.Tim
True, _
UserInfo.RoleNames) ', _
'FormsAuthentication.Forms
'Encrypt the ticket and put it into the cookie
strHash = FormsAuthentication.Encryp
cookie = New HttpCookie(FormsAuthentica
'Set the cookie's expiration time to the ticket's expiration time
If ticket.IsPersistent Then
cookie.Expires = ticket.Expiration
'Add the cookie to the list for outgoing response
Response.Cookies.Add(cooki
End If
Server.Transfer(strTransfe
END CODE A --- END CODE A --- END CODE A --- END CODE A
CODE B --- CODE B --- CODE B --- CODE B --- CODE B
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Session Variables Available: EID, Login, LoginID, FName, LName
'Reset the session timeout
If Not Page.IsPostBack Then
Response.AppendHeader("Ref
ifContent.Attributes.Add("
'Set Login Name
lblLogin.Text = " " + Session("FName") + " " + Session("LName") + " is logged in."
'If no current user, then return to default page.
If Session("Login") = "" Then
Response.Redirect("../defa
Exit Sub
End If
'Set menu visibility
pnlMainMenu.Visible = True
If User.IsInRole("Administrat
END CODE B --- END CODE B --- END CODE B --- END CODE B --- END CODE B
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
When you use form authentication, the user idtentity is not set automatically by asp .net since it requires anonymous access. Thus you have to populate the user identity yourself.
ASKER
(Answering two questions with one post...)
Yes, I do have code in Global.asax. I just forgot to post it or mention it. Here is what I have:
GLOBAL.ASAX CODE --- GLOBAL.ASAX CODE --- GLOBAL.ASAX CODE --- GLOBAL.ASAX CODE
Sub Application_AuthenticateRe quest(ByVa l sender As Object, ByVal e As EventArgs)
' Fires upon attempting to authenticate the use
'This code assembles the user's credentials on the fly.
'If there is a current user and they are authenticated and FormsIdentity is being used,
If Not (HttpContext.Current.User Is Nothing) Then
If HttpContext.Current.User.I dentity.Is Authentica ted Then
If TypeOf HttpContext.Current.User.I dentity Is FormsIdentity Then
Dim fi As FormsIdentity = CType(HttpContext.Current. User.Ident ity, FormsIdentity)
Dim fat As FormsAuthenticationTicket = fi.Ticket
Dim astrRoles As String() = fat.UserData.Split(",")
HttpContext.Current.User = New GenericPrincipal(fi, astrRoles)
FormsAuthentication.RenewT icketIfOld (fat)
End If
End If
End If
End Sub
END GLOBAL.ASAX --- END GLOBAL.ASAX --- END GLOBAL.ASAX --- END GLOBAL.ASAX ---
I take it that this code is not populating the user identity, so that code must be missing. Can you show me what code I need and where?
Yes, I do have code in Global.asax. I just forgot to post it or mention it. Here is what I have:
GLOBAL.ASAX CODE --- GLOBAL.ASAX CODE --- GLOBAL.ASAX CODE --- GLOBAL.ASAX CODE
Sub Application_AuthenticateRe
' Fires upon attempting to authenticate the use
'This code assembles the user's credentials on the fly.
'If there is a current user and they are authenticated and FormsIdentity is being used,
If Not (HttpContext.Current.User Is Nothing) Then
If HttpContext.Current.User.I
If TypeOf HttpContext.Current.User.I
Dim fi As FormsIdentity = CType(HttpContext.Current.
Dim fat As FormsAuthenticationTicket = fi.Ticket
Dim astrRoles As String() = fat.UserData.Split(",")
HttpContext.Current.User = New GenericPrincipal(fi, astrRoles)
FormsAuthentication.RenewT
End If
End If
End If
End Sub
END GLOBAL.ASAX --- END GLOBAL.ASAX --- END GLOBAL.ASAX --- END GLOBAL.ASAX ---
I take it that this code is not populating the user identity, so that code must be missing. Can you show me what code I need and where?
where did u get "UserInfo.RoleNames"?
by the way, did you configure your web.config to be FormsAuthentication?
In your global.asax, your code will never execute. Because your code to populate identity only executes if user.identity is populated. That can never happen. It's a cycle.
The correct way is to get the authentication ticket from cookie, and if that cookie exists, you populate your user.identity as in your code.
The correct way is to get the authentication ticket from cookie, and if that cookie exists, you populate your user.identity as in your code.
ASKER
UserInfo is a class that I created. RoleNames is a property of that class that returns a comma-delimited listed of role names which I fetched from the database.
ASKER
I put a bunch a breakpoints in my code to track the execution of what happens when:
1. Global.asax/Application_Au thenticate Request (skips processing of user)
2. Login.aspx/Page_Load, waits for user to enter credentials and press ENTER
3. Global.asax/Application_Au thenticate Request (skips processing of user)
4. Login.aspx/Page_Load for postback processing (I don't have any)
5. Login.aspx/Btn_Click event where tickets and cookies are created and set
6. Main.aspx/Page_Load, checks for user roles and finds nothing
7. Global.aspx/Application_Au thenticate Request, finally processes user and roles, but too late for step 6 to use
8. Main.aspx/ read for data entry
So the root problem is that steps 6 and 7 need to be switched, because as it stands the user and user roles are processed after the Main.aspx from has already checked for them. I tried copying the step 7 code into Step 5 (put at the end of CODE A sample above) so it would process the user/roles sooner, but it refuses to do it. It just skips over it. So I am in a quandary. I need step 7 to process before step 6 but it won't.
Any ideas?
1. Global.asax/Application_Au
2. Login.aspx/Page_Load, waits for user to enter credentials and press ENTER
3. Global.asax/Application_Au
4. Login.aspx/Page_Load for postback processing (I don't have any)
5. Login.aspx/Btn_Click event where tickets and cookies are created and set
6. Main.aspx/Page_Load, checks for user roles and finds nothing
7. Global.aspx/Application_Au
8. Main.aspx/ read for data entry
So the root problem is that steps 6 and 7 need to be switched, because as it stands the user and user roles are processed after the Main.aspx from has already checked for them. I tried copying the step 7 code into Step 5 (put at the end of CODE A sample above) so it would process the user/roles sooner, but it refuses to do it. It just skips over it. So I am in a quandary. I need step 7 to process before step 6 but it won't.
Any ideas?
Is your code ever executed when you were debugging?
ASKER
Yes. The code runs to completion successfully every time.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I have figured out the problem.
The last line of CODE A is:
Server.Transer(strTransfer To)
It should be:
Response.Redirect(strTrans ferTo)
The purpose of CODE A is to prepare the authentication ticket and write it into a cookie and put it on the client. Response.Redirect causes the cookie containing the forms authentication ticket with the user's info and roles to be set on on the client. The Server.Transfer method I used does not do this. Making this one changes causes everything to work.
The last line of CODE A is:
Server.Transer(strTransfer
It should be:
Response.Redirect(strTrans
The purpose of CODE A is to prepare the authentication ticket and write it into a cookie and put it on the client. Response.Redirect causes the cookie containing the forms authentication ticket with the user's info and roles to be set on on the client. The Server.Transfer method I used does not do this. Making this one changes causes everything to work.
ASKER
Even though neither help directly answered the question, they provided pointers which helped me think through the problem better. The link referenced by Testn is an excellent, comprehensive analysis of how to implement forms authentication. Highly recommended. Laotzi2000's alternate form for authenticating helped me compare two methods of doing the same thing and understand the dynamics of what is going on.
This area of functionality is utterly confusing for people new to ASP.NET. Thanks for helping.
This area of functionality is utterly confusing for people new to ASP.NET. Thanks for helping.