Answered by:
Inconsistency using UserPrincipal in website

Question
-
User-1638436556 posted
I am working on a few different websites that are ASP.net for the company I work at. Where I work we use windows authentication. I was starting to use the UserPrincipal object to determine who the current authenticated user was that was in my site. I am showing the current user name in my master.page header. It seems to work EXCEPT it seems to pick up other people's sessions. If I have a couple of the developers in my department to all hit the site and pages at the same time, we sometimes get other peoples names displayed in our page.
I currently have my code to determine who is in the site on the Session_Start method in the global.asax file which is probably my mistake but where should I put this code so that I only have to run it once and only get the current user?
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "domainname");
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, HttpContext.Current.User.Identity.Name);Wednesday, February 28, 2018 1:40 PM
Answers
-
User475983607 posted
Bottom line, I am wanting to see if it makes sense to just call the PrincipalContext code one time and if so where?Yes, it makes sense to cache data. Only grab the data if the cache has expired.
And if I can call it once, what makes more sense to store it in? Session[] or some sort of Class object.You've been given several suggestions.
The username is always available via...
HttpContext.Current.User.Identity.Name
So there is no need to store the username.
If you have other items you would like to persist, I suggest using a cookie.
https://msdn.microsoft.com/en-us/library/ms178194.aspx
PatriceSc provided a nice example that shows how to store the principal in Session. I'm not a fan of Session due to reasons mentioned above but that does not mean it is not a solid solution for you.
or some sort of Class object.A class holds the data during the request. You'll need to find an ASP State Management feature that persists data between requests. See the following link.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, March 1, 2018 9:12 PM
All replies
-
User753101303 posted
Hi,
Usually it happens when using static data which are class level and shared by all users. Double check where you are storing the user information you are reading from the UserPrincipal.
Not directly related but you could use something such as https://www.codeproject.com/articles/16656/manage-asp-net-session-variables-using-the-facade (it will be loaded as needed and "cached" as session values plus you have strongly typed value, IntelliSense support etc...)
Wednesday, February 28, 2018 1:59 PM -
User-1638436556 posted
I am using a class to store my user info in...
ADUser.UserName = user.Name ?? ""; //if the user.username is null, put "" in it.
--my class
public static class ADUser
{}
what should this be?
Wednesday, February 28, 2018 2:02 PM -
User-1638436556 posted
Instead of using a class for my User should I just do something like:
Session["UserName"] = user.Name?
Wednesday, February 28, 2018 2:08 PM -
User283571144 posted
Hi jeff573,
Instead of using a class for my User should I just do something like:
Session["UserName"] = user.Name?
If you're using the default InProc session state, it's only stored in RAM, so it can go away not only when the session times out, but also if the AppPool recycles, which can happen for a number of reasons (idle timeouts, once daily, excessive memory use, etc). In addition, session state is locked by each page, so if your app tries to do multiple accesses at once, you can run into issues. We couldn't access the session access the web application.
How large is your User object? If it's not too huge, you might consider storing the data in a cookie, rather than in session state.
Best Regards,
Brando
Thursday, March 1, 2018 5:25 AM -
User753101303 posted
You could. But prefer as shown above to use session as a cache rather than loading it once for all so that the value can be reloaded as needed.
Thursday, March 1, 2018 9:08 AM -
User-1638436556 posted
We will be writing a few different website for our Business Intelligence (dashboards, etc). I was trying to write a class that would handle this information but made the mistake of creating the class as Static. So now I am trying to determine what is the best method of capturing this user data for a user when they run one of the websites and display the current user's name/AD info. I can pull the AD data, but not sure how and when I should store it.
Thursday, March 1, 2018 3:17 PM -
User475983607 posted
Confused... Windows authentication automatically populates the principle with the username on each request. This is how Windows authentication works fundamentally.
Then if you need more user info, simply look it up.
Thursday, March 1, 2018 6:12 PM -
User-1638436556 posted
I believe the issue I was originally having was I was trying to get the userPrinciple value on the Session_Start of the site and then storing these values in a static class.
From what I am reading, I should instead:
1) when I want to display the current user on a page, use:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "domainname");
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, HttpContext.Current.User.Identity.Name);2) put the UserPrincipal user values into Session[""] values and then use Session[""] when i want to display the information on the page.
If I am wrong, please someone tell me.
But, if I do the #2 option of loading the UserPrincipal user values into Session[""]'s...when do I load up the Session[""] values?
Thursday, March 1, 2018 6:42 PM -
User753101303 posted
The quickest change might be something such as :
public static class ADUser { public static string DisplayName { get { var displayName=System.Web.Context.Current.Session["ADUser.DisplayName"]; if(String.IsNullOrEmpty(displayName)) { using (var context = new PrincipalContext(ContextType.Domain)) { var usr = UserPrincipal.FindByIdentity(context, User.Identity.Name); displayName= usr.DisplayName; Session["ADUser.DisplayName"]=displayName; } } return displayName; } } }
The problem is really with static DATA. You can keep your static class and even a static property as long as the underlying value is stored in a non static source (here browser session scope).
Also it will be just loaded when first needed (and it will be reloaded if the value is lost for some reason). Finally your main code doesn't care about the underlying storage and you could later move to something else if you want...
Thursday, March 1, 2018 6:53 PM -
User475983607 posted
If I am wrong, please someone tell me.
But, if I do the #2 option of loading the UserPrincipal user values into Session[""]'s...when do I load up the Session[""] values?
Your end goal is not clear. Obviously, the username is always available because you're using Windows Authentication in IIS.
The posted code uses the username to look up the UserPrincipal in directory services. From there you can access properties and methods of the the UserPrincipal instance. What is the purpose of placing the UserPrincipal in Session? If you just need a handful of properties to display on the page then, just put the values you want to persist in a cookie.
Session works too but Session has limitation as it lives in server memory and can affect async requests as pointed out by Brando ZWZ.
Thursday, March 1, 2018 7:06 PM -
User-1638436556 posted
Ok, here is my original issue.
I was told I could use the following code to get the current windows authenticated user that is running the web page.
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "domainname");
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, HttpContext.Current.User.Identity.Name);I had originially put this in the page load of my master.page so that I could display user.UserName or user.SamAccountName, etc. This seemed to work just fine.
Then I thought, is there a way I can call the PrincipalContext object ONE time in my website and store that data in a class because I will use it throughout the website. Not only in the Master.Page (hello 'Jeff') header, but I also use the SamAccountName string in my insert and update stored procedures so that I can track in my data 'who' made the changes.So I thought I would create a class (called ADUser) to store this information in. So (maybe first mistake) I created a static class called ADUser and then in my Global.asax on session_Start I had this code:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "domainname");
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, HttpContext.Current.User.Identity.Name);ADUser.UserName = user.Name;
ADUser.DisplayName = user.DisplayName;
etc.This seemed to work just fine until I had a couple of the users all try and browse the same page at the same time...Then I might have User A see 'Hello User B' randomly, so I knew I had an issue. I then read where Static classes are shared so I thought maybe this is the issue, my ADUser class is defined as Static.
Then I read where I should use Session[""] to hold my AD user information instead. But if I do that (i.e. Session["UserName"] = user.Name;, i was hoping I could just create/call the (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "domainname");UserPrincipal user = UserPrincipal.FindByIdentity(ctx, HttpContext.Current.User.Identity.Name);) code one time.Bottom line, I am wanting to see if it makes sense to just call the PrincipalContext code one time and if so where? And if I can call it once, what makes more sense to store it in? Session[] or some sort of Class object.
Hopefully this makes sense.
Thursday, March 1, 2018 7:44 PM -
User475983607 posted
Bottom line, I am wanting to see if it makes sense to just call the PrincipalContext code one time and if so where?Yes, it makes sense to cache data. Only grab the data if the cache has expired.
And if I can call it once, what makes more sense to store it in? Session[] or some sort of Class object.You've been given several suggestions.
The username is always available via...
HttpContext.Current.User.Identity.Name
So there is no need to store the username.
If you have other items you would like to persist, I suggest using a cookie.
https://msdn.microsoft.com/en-us/library/ms178194.aspx
PatriceSc provided a nice example that shows how to store the principal in Session. I'm not a fan of Session due to reasons mentioned above but that does not mean it is not a solid solution for you.
or some sort of Class object.A class holds the data during the request. You'll need to find an ASP State Management feature that persists data between requests. See the following link.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, March 1, 2018 9:12 PM