?
Solved

ASP.NET: User.Identity.Name and User.IsInRole() not getting populated the first time

Posted on 2005-03-07
13
Medium Priority
?
1,505 Views
Last Modified: 2008-01-09
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.Timeout), _
                                                   True, _
                                                   UserInfo.RoleNames)   ', _
         'FormsAuthentication.FormsCookiePath)

         'Encrypt the ticket and put it into the cookie
         strHash = FormsAuthentication.Encrypt(ticket)
         cookie = New HttpCookie(FormsAuthentication.FormsCookieName, 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(cookie)
         End If

         Server.Transfer(strTransferTo)

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("Refresh", Convert.ToString((Session.Timeout * 60) + 10) & "; url=http://www.mychurchdata.com/Login.aspx")
         ifContent.Attributes.Add("Src", "Users/Main.aspx?Return=Postback")

         '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("../default.aspx")
            Exit Sub
         End If

         'Set menu visibility
         pnlMainMenu.Visible = True
         If User.IsInRole("Administrator") = True Then pnlAdminMenu.Visible = True     'SET BREAKPOINT HERE

END CODE B   ---   END CODE B   ---   END CODE B   ---   END CODE B   ---   END CODE B

0
Comment
Question by:rgrimm
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
  • 3
13 Comments
 
LVL 18

Assisted Solution

by:testn
testn earned 1000 total points
ID: 13482865
Make sure that you have the code to authenticate the user first in your Global.asax. Check this site for more detail
http://www.xoc.net/works/tips/forms-authentication.asp
0
 
LVL 12

Expert Comment

by:laotzi2000
ID: 13482914
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.
0
 

Author Comment

by:rgrimm
ID: 13483358
(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_AuthenticateRequest(ByVal 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.Identity.IsAuthenticated Then
                If TypeOf HttpContext.Current.User.Identity Is FormsIdentity Then
                    Dim fi As FormsIdentity = CType(HttpContext.Current.User.Identity, FormsIdentity)
                    Dim fat As FormsAuthenticationTicket = fi.Ticket

                     Dim astrRoles As String() = fat.UserData.Split(",")
                    HttpContext.Current.User = New GenericPrincipal(fi, astrRoles)
                    FormsAuthentication.RenewTicketIfOld(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?
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 18

Expert Comment

by:testn
ID: 13483417
where did u get "UserInfo.RoleNames"?
0
 
LVL 18

Expert Comment

by:testn
ID: 13483421
by the way, did you configure your web.config to be FormsAuthentication?
0
 
LVL 12

Expert Comment

by:laotzi2000
ID: 13483590
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.
0
 

Author Comment

by:rgrimm
ID: 13483747
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.
0
 

Author Comment

by:rgrimm
ID: 13483823
I put a bunch a breakpoints in my code to track the execution of what happens when:

1. Global.asax/Application_AuthenticateRequest (skips processing of user)
2. Login.aspx/Page_Load, waits for user to enter credentials and press ENTER
3. Global.asax/Application_AuthenticateRequest (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_AuthenticateRequest, 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?
0
 
LVL 12

Expert Comment

by:laotzi2000
ID: 13483857
Is your code ever executed when you were debugging?
0
 

Author Comment

by:rgrimm
ID: 13487754
Yes. The code runs to completion successfully every time.
0
 
LVL 12

Accepted Solution

by:
laotzi2000 earned 1000 total points
ID: 13488642
Don't think this code will work:
        If Not (HttpContext.Current.User Is Nothing) Then
            If HttpContext.Current.User.Identity.IsAuthenticated Then
                If TypeOf HttpContext.Current.User.Identity Is FormsIdentity Then
                    Dim fi As FormsIdentity = CType(HttpContext.Current.User.Identity, FormsIdentity)
                    Dim fat As FormsAuthenticationTicket = fi.Ticket

                     Dim astrRoles As String() = fat.UserData.Split(",")
                    HttpContext.Current.User = New GenericPrincipal(fi, astrRoles)
                    FormsAuthentication.RenewTicketIfOld(fat)
                End If
            End If
        End If

My suggestion:
  Dim authCookie as HttpCookie = Context.Request.Cookies(FormsAuthentication.FormsCookieName)
  if (authCookie is nothing) then
    return
  end if
  dim ticket as FormsAuthenticationTicket
  try
    ticket = FormsAuthentication.Decrypt(authCookie.value)
  catch
    return
  end try
  If ticket is nothing then
    return
  end if
  Dim id as FormsIdentity = new FormsIdentity(ticket)
  dim roles as string() = ticket.UserData.Split(",")
  Context.User = new GenericPrincipal(id, roles)
0
 

Author Comment

by:rgrimm
ID: 13490365
I have figured out the problem.

The last line of CODE A is:

     Server.Transer(strTransferTo)

It should be:

    Response.Redirect(strTransferTo)

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.
0
 

Author Comment

by:rgrimm
ID: 13490423
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.
0

Featured Post

New benefit for Premium Members - Upgrade now!

Ready to get started with anonymous questions today? It's easy! Learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Sometimes in DotNetNuke module development you want to swap controls within the same module definition.  In doing this DNN (somewhat annoyingly) swaps the Skin and Container definitions to the default admin selections.  To get around this you need t…
I recently went through the process of creating a Calendar Control of events with the basis of using a database to keep track of the dates that are selectable, one requirement was to have the selected date pop-up in a simple lightbox.  At first this…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…
In this video, Percona Solution Engineer Rick Golba discuss how (and why) you implement high availability in a database environment. To discuss how Percona Consulting can help with your design and architecture needs for your database and infrastr…
Suggested Courses

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question