Answered by:
Accessing Claims Value After Login

Question
-
User1863794983 posted
Hi all.
I'm using .NET 4.5 MVC. I'm new to MVC but I don't think that's the problem.
I'm stumped. I have a user that has a custom claim, FullName, and I don't know how to access it after signing in. I can verify that the claim exists in the AspNetUserClaims table. The user is authenticated. I'm not on the Login screen, nor even the screen after that. I'm in the middle of a normal session.
I'd like to use the FullName claim in the MVC _LoginPartial.cshtml file so it says "Welcome, [FullName]." I've done a ton of googling around and all the methods for accessing claims boils down to these two methods, which both do not work for me.
//Method 1 var identity = (System.Security.Claims.ClaimsIdentity)Context.User.Identity; var claim1 = identity.Claims.FirstOrDefault(c => c.Type == "FullName"); //Method 2 var principal = System.Security.Claims.ClaimsPrincipal.Current; System.Security.Claims.Claim claim2 = principal.FindFirst("FullName");
In the above examples, both claim1 and claim2 evaluate to null.
I found this blog which suggests that what I'm trying to do is impossible. Is that so?
The whole reason I'm using claims is so I can store a little bit of extra information on a user. Historically I"d add some columns to the aspnet_Membership table and I'd have to customize the Membership classes to account for the new columns, so claims looked a lot easier, but I've wasted so much time trying to get them to work! Any help is appreciated!
EDIT: This code DOES work during the login process, in AccountController.cs, Login(model, returnUrl):
//Method 3 var user = UserManager.FindByName(model.UserName); string fn = user.Claims.FirstOrDefault(c => c.ClaimType == "FullName").ClaimValue;
So, that's another way I know the claim exists. I do not know how to use this in _LoginPartial.cshtml because I do not know how to access UserManager there.
Wednesday, September 21, 2016 6:29 PM
Answers
-
User1863794983 posted
My problem is fixed.
I had another issue that I had forgotten about that turned out to be affecting my claims. Specifically, in my AccountController.cs, I was missing await SignInAsync(). I did have a FormsAuthentication.SetAuthCookie(). As a result, my user was authenticated, but had no ID (or Claims). Adding SignInAsync() solved both problems (missing ID and missing Claims).
Answer:
Both methods work fine for accessing a claim value post-login if the user is authenticated and has been signed in.
//Method 1 var identity = (System.Security.Claims.ClaimsIdentity)Context.User.Identity; string fullname1 = identity.Claims.FirstOrDefault(c => c.Type == "FullName").Value; //Method 2 var principal = System.Security.Claims.ClaimsPrincipal.Current; string fullname2 = principal.FindFirst("FullName").Value;
I do not see any need to mess with ClaimsIdentityFactory.
For the record, I'm using .NET 4.5, MVC 5, Identity Framework (user profile is in application database but password is NULL), and a custom LDAP authentication (not using a Provider).
Thank you, BrockAllen for your help!
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, September 22, 2016 6:38 PM
All replies
-
User1779161005 posted
The first two approaches are trying to load the claims from the cookie. The third approach is querying the DB. IF the claims are not present in the cookie, then it means at login time you're not issuing those claims in the cookie. If you're using ASP.NET Identity for the user database, then you should implement a custom ClaimsIdentityFactory to issue those claims.
Wednesday, September 21, 2016 6:56 PM -
User1863794983 posted
Hello, BrockAllen. Pointing me to ClaimsIdentityFactory was helpful, I think. This is a whole can of worms that I was not expecting. (I was expecting adding claims to be easier than this.)
Per your advice, I wrote this:
public class ApplicationClaimsIdentityFactory : ClaimsIdentityFactory<ApplicationUser> { public string FullName { get; set; } public async override Task<ClaimsIdentity> CreateAsync( UserManager<ApplicationUser, string> manager, ApplicationUser user, string authenticationType) { var identity = await base.CreateAsync(manager, user, authenticationType); identity.AddClaim(new Claim("FullName", FullName)); return identity; } }
And then I wrote this just before the cookie is set at login (in Login(model, returnUrl)):
//Method 3 var user = UserManager.FindByName(model.UserName); string fn = user.Claims.FirstOrDefault(c => c.ClaimType == "FullName").ClaimValue; UserManager.ClaimsIdentityFactory = new ApplicationClaimsIdentityFactory() { FullName = fn };
On _LoginPartial.cshtml, I tried accessing this value using Method 1 and Method 2 above, but they still yield null. What am I missing?
Given this headache for something as small as a FullName, I'm thinking the old-fashioned Session variable is more up to the task. What do you think?
Thank you for your time!
Wednesday, September 21, 2016 8:37 PM -
User1779161005 posted
> Given this headache for something as small as a FullName, I'm thinking the old-fashioned Session variable is more up to the task. What do you think?
I think session state is awful: https://brockallen.com/2012/04/07/think-twice-about-using-session-state/
Wednesday, September 21, 2016 9:35 PM -
User1863794983 posted
Hello, BrockAllen. I just realized you are the author of the blog I linked!
I appreciate your sentiments about Session and you opened my eyes to the data Cache, which has some nice added stuff but has the same drawback as Session: you have to check if its value is lost.
I'm experimenting with Cache now. On authentication, I put the FullName into the data cache and on _LoginPartial.cshtml, I pull from the cache. This works great. The problem is how to gracefully deal with the situation when the cache is cleared. On Microsoft's site, they say to test for null and repopulate the value.
My question -- still on-topic for this thread -- is how do I query the database for the user claims when I'm not authenticating? In other words, how do I use Method 3 outside of AccountController.cs?
Your first reply might be good to mark as answered but it is not clear to me how to issue a claim in the cookie using a custom ClaimsIdentityFactory. At the end of the day I still cannot access claims values after login.
Thank you for your time!
Thursday, September 22, 2016 2:46 PM -
User1863794983 posted
My problem is fixed.
I had another issue that I had forgotten about that turned out to be affecting my claims. Specifically, in my AccountController.cs, I was missing await SignInAsync(). I did have a FormsAuthentication.SetAuthCookie(). As a result, my user was authenticated, but had no ID (or Claims). Adding SignInAsync() solved both problems (missing ID and missing Claims).
Answer:
Both methods work fine for accessing a claim value post-login if the user is authenticated and has been signed in.
//Method 1 var identity = (System.Security.Claims.ClaimsIdentity)Context.User.Identity; string fullname1 = identity.Claims.FirstOrDefault(c => c.Type == "FullName").Value; //Method 2 var principal = System.Security.Claims.ClaimsPrincipal.Current; string fullname2 = principal.FindFirst("FullName").Value;
I do not see any need to mess with ClaimsIdentityFactory.
For the record, I'm using .NET 4.5, MVC 5, Identity Framework (user profile is in application database but password is NULL), and a custom LDAP authentication (not using a Provider).
Thank you, BrockAllen for your help!
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, September 22, 2016 6:38 PM -
User1779161005 posted
You should also remove the call to FormsAuthentication -- that's not needed anymore.
Thursday, September 22, 2016 8:51 PM