29

I've extended the ASP NET identity schema by adding few fields in the ApplicationUser Class which is derived from IdentityUser. One of the field that I've added is FullName.

Now, when I write User.Identity.Name, it gives me the user name, I m looking for something like User.Identity.FullName which should return the FullName that I have added.

Not sure, how this can be achieved any guidance shall be greatly appreciated.

Thanks.

Ashish Charan
  • 2,347
  • 4
  • 21
  • 33

8 Answers8

27

In the ApplicationUser class, you'll notice a comment (if you use the standard MVC5 template) that says "Add custom user claims here".

Given that, here's what adding FullName would look like:

public class ApplicationUser : IdentityUser
{
    public string FullName { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        userIdentity.AddClaim(new Claim("FullName", this.FullName));
        return userIdentity;
    }
}

Using this, when someone logs in, the FullName claim will be put in the cookie. You could make a helper to access it like this:

    public static string GetFullName(this System.Security.Principal.IPrincipal usr)
    {
        var fullNameClaim = ((ClaimsIdentity)usr.Identity).FindFirst("FullName");
        if (fullNameClaim != null)
            return fullNameClaim.Value;

        return "";
    }

And use the helper like this:

@using HelperNamespace
...
@Html.ActionLink("Hello " + User.GetFullName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })

Note that custom user claims are stored in the cookie and this is preferable to getting the user info from the DB... saves a DB hit for commonly accessed data.

Marcel
  • 403
  • 4
  • 7
  • 2
    Where do I put: public static string GetFullName(this System.Security.Principal.IPrincipal usr) – Dev Jun 10 '16 at 12:26
  • 3
    @Decoder94 - In a helper or utility class, and then add the namespace to the view. In my case, I have a class called Utilities.cs in the Models folder. I put the `GetFullName()` method in there. I then added `@using myProject.Models` to the view. – devlin carnate Aug 18 '17 at 22:34
  • @Decoder94 i was trying to get profile picture path as claim. but i got `Value cannot be null. Parameter name: value` error. what to do when there can be null value? – Ahashan Alam Sojib Sep 30 '18 at 16:18
  • I had to put the GetFullName method inside of a public static class YourClassName inside the IdentityModels.cs – Scott Ridings Dec 01 '19 at 06:59
26

You could add it to the User's claims when you create the user and then retrieve it as a claim from the User.Identity:

await userManager.AddClaimAsync(user.Id, new Claim("FullName", user.FullName));

Retreive it:

((ClaimsIdentity)User.Identity).FindFirst("FullName")

Or you could just fetch the user and access it off of the user.FullName directly:

var user = await userManager.FindById(User.Identity.GetUserId())
return user.FullName
Hao Kung
  • 28,040
  • 6
  • 84
  • 93
  • 2
    Thanks for your solution. I am wondering, if I store this data as Claims, does it gets added to the Authentication cookie? I'd like to have some user data always available in my views to integrate intercom.io. Thanks – Pedro Alonso Jan 21 '15 at 01:59
  • Can you specify where exactly i can add the first line? I want to be able to capture the user to store it but also really want the first name as well. – Mostafa Mar 12 '19 at 21:42
  • After `.FindFirst("FullName")`, I had to add `.Value` to actually get the value. – Rachel Martin Apr 18 '19 at 14:40
12

I have found that this works pretty well

AccountController:

private async Task SignInAsync(ApplicationUser user, bool isPersistent)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
        var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
        identity.AddClaim(new Claim("FullName", user.FullName));
        identity.AddClaim(new Claim("Email", user.Email));
        identity.AddClaim(new Claim("DateCreated", user.DateCreated.ToString("MM/dd/yyyy")));
        AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
    }

Extension Method on Identity:

 public static class GenericPrincipalExtensions
{
    public static string FullName(this IPrincipal user)
    {
        if (user.Identity.IsAuthenticated)
        {
            ClaimsIdentity claimsIdentity = user.Identity as ClaimsIdentity;
            foreach (var claim in claimsIdentity.Claims)
            {
                if (claim.Type == "FullName")
                    return claim.Value;
            }
            return "";
        }
        else
            return "";
    }
}

In your View:

 @Html.ActionLink("Hello " + User.FullName() + "!", "Manage", "Account", routeValues: null, htmlAttributes: new { title = "Manage" })

You can look at the thread here: Link

H20rider
  • 2,162
  • 5
  • 29
  • 47
4

It is possible by defining your own IIdentity (and possibly IPrincipal too) and constructing this when creating the IPrincipal for the HTTP request (when PostAuthenticateRequest is raised).

How to implement your own IIDentity and IPrincipal: How do I implement custom Principal and Identity in ASP.NET MVC?

Community
  • 1
  • 1
Paweł Bejger
  • 6,176
  • 21
  • 26
  • When I was searching internet for the same, I reached the same place as pointed by you. But I found that way long and that answer seemed pretty old(3-4 years). I was thinking that may be the people at Microsoft must have advised a new and simpler way to do this. – Ashish Charan Jan 26 '14 at 11:47
  • What is the reasoning behind the fact that you want to store FullName in your User.Identity? Is this because you want to access this on every page or there is some other reason? – Paweł Bejger Jan 26 '14 at 11:53
  • 1
    In my case when I needed some data (like the FullUserName) that I wanted to be displayed on each page of the application I simply put it to my BaseViewModel which was a base class for every view model I used + I populated my BaseViewModel in my BaseController class which was a base class for every controller that I used (so its constructor was always executed). – Paweł Bejger Jan 26 '14 at 12:12
3

Store value to claims and read it.

Store Value

public class ApplicationUser : IdentityUser
{
    public string FullName { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);

        userIdentity.AddClaim(new Claim("FullName", this.FullName));

        return userIdentity;
    }
}

Read Value

var FullName = "";
if (User != null)
{
    var identity = (System.Security.Claims.ClaimsIdentity)Context.User.Identity;
    var claim1 = identity.Claims.FirstOrDefault(c => c.Type == "FullName");
    if (claim1 != null)
    {
        FullName = claim1.Value;
    }
}
Arun Prasad E S
  • 9,489
  • 8
  • 74
  • 87
2

I solved the problem by doing the following:

1 - Create my own CustomPrincipal by extending IPrincipal

2 - Load the CustomPrincipal after each request has been authenticated.

Create my own CustomPrincipal

interface ICustomPrincipal : IPrincipal
{
    string UserId { get; set; }
    string FirstName { get; set; }
    string LastName { get; set; }
    int CustomerId { get; set; }
}

public partial class CustomPrincipal : ClaimsPrincipal, ICustomPrincipal
{
    #region IPrincipal Members
    public new ClaimsIdentity Identity { get; private set; }
    public new bool IsInRole(string role)
    {
        IdentityManager manager = new IdentityManager();
        return manager.IsInRole(role, this.UserId);
    }
    #endregion

    public CustomPrincipal(ApplicationUser user, IIdentity identity)
        :base(identity)
    {
        this.Identity = new ClaimsIdentity(identity);
        this.UserId = user.Id;
        this.FirstName = user.FirstName;
        this.LastName = user.LastName;
        this.CustomerId = user.CustomerId;
        this.DateCreated = user.DateCreated;
    }

    #region ICustomPrinicpal Members
    public string UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int CustomerId { get; set; }
    public DateTime DateCreated { get; set; }
    #endregion

    public string GetFullName()
    {
        return this.FirstName + " " + this.LastName;
    }
}

Load the CustomPrincipal after each request has been authenticated

In the Global.asax.cs...

    protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
    {
        if (User.Identity.IsAuthenticated)
        {
            //At this point we need to get the user from the database based on the username. 
            ApplicationUser AppUser = ApplicationUserDB.GetByUserName(User.Identity.Name);
            CustomPrincipal UserPrincipal = new CustomPrincipal(AppUser, User.Identity);
            HttpContext.Current.User = UserPrincipal;
        }
    }

As you can see in my code above, I retrieve an ApplicationUser and pass it in the constructor of the CustomPrincipal. I then assign the new CustomPrincipal to the current context.

FrankO
  • 2,522
  • 6
  • 24
  • 34
1

This should do the trick:

User.Claims.Single(x => x.Type== "name").Value
brasofilo
  • 25,496
  • 15
  • 91
  • 179
  • For some reason this only works for me if I use `User.Claims.SingleOrDefault(c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname").Value`. I derived the URI with the schema by grabbing the claims for the user in debug. – Philip Stratford Apr 15 '20 at 15:36
0

I tried this and it works!

IdentityModels.cs/ApplicationUser Class

// Add custom user claims here
        userIdentity.AddClaim(new Claim("FullName", this.FullName));

_LoginPartialView

    <li>
@Html.ActionLink("Hello " +  (((ClaimsIdentity)User.Identity).FindFirst("FullName").Value) + " !", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
    </li>