Home How to add claims to the HttpContext User on sign in
Reply: 1

How to add claims to the HttpContext User on sign in

dinotom
1#
dinotom Published in 2017-11-12 22:47:28Z

This post may be long, but will have all the pertinent detail required for an answer.

I have been searching, and found that many others have as well, for the proper methodology to add claims to the HttpContext User so that those claims can be retrieved when needed, using Razor, in a view.

For example,

In the default Asp.Net Core 2.0 web application, the _LoginPartial has code that displays the users email. If I wanted to change that to the users full name (this assumes the registration process includes the first and last name entries, with the appropriate changes to the ApplicationUser class)

 // Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public DateTime DateOfBirth { get; set; }

    public Gender Gender { get; set; }
    ...balance of code removed for brevity
}

I would want to add a claim on the User for their full name and gender to use instead of the UserManager method currently employed in the default app. (And others down the road)

Current default wep app code

@if (SignInManager.IsSignedIn(User))
{
    <form asp-area="" asp-controller="Account" asp-action="Logout" method="post" id="logoutForm" class="navbar-right">
        <ul class="nav navbar-nav navbar-right">
            <li>
                <a asp-area="" asp-controller="Manage" asp-action="Index" title="Manage">Hello @UserManager.GetUserName(User)!</a>
            </li>
            <li>
                <button type="submit" class="btn btn-link navbar-btn navbar-link">Log out</button>
            </li>
        </ul>
    </form>
}
else
{
...code removed for brevity
}

What I am hoping to accomplish; Replacing this,

<a asp-area="" asp-controller="Manage" asp-action="Index" title="Manage">Hello @UserManager.GetUserName(User)!</a>

with this

<a asp-area="" asp-controller="Manage" asp-action="Index" title="Manage">Hello @((ClaimsIdentity) User.Identity).GetSpecificClaim("avatarUrl")!</a>    

Note: GetSpecificClaim is an extension method to retrieve the claim.

I believe the best place to add the claims would be in the login method.

 public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
         if (!ModelState.IsValid) return View(model);
        // Now model is valid, require the user to have a confirmed email before they can log on.
        var user = await _userManager.FindByEmailAsync(model.Email);
        if (user != null)
        {
            if (!await _userManager.IsEmailConfirmedAsync(user))
            {
                ModelState.AddModelError(string.Empty,
                    "You must have a confirmed email to log in.");
                return View(model);
            }
        }
        else
        {
            ModelState.AddModelError(string.Empty,
                "There is no registered account for the email address supplied.");
            return View(model);
        }

        var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");

            // Add claims to signed in user 
            var userClaims = HttpContext.User.Claims.ToList();
            userClaims.Add(new Claim("fullname", user.GetFullName(user.UserName)));
            userClaims.Add(new Claim("avatarUrl", user.AvatarUrl));

           // Using ClaimsTransformer
           // Add claims here for the logged in user using AddUserInfoClaimsAsync extension method
            **var ct = new ClaimsHelpers.ClaimsTransformer();
            var identityWithInfoClaims = await ct.AddUserInfoClaimsAsync(User, user);**

            return RedirectToLocal(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToAction(nameof(LoginWith2Fa), new { returnUrl, model.RememberMe });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToAction(nameof(Lockout));
        }

        ModelState.AddModelError(string.Empty, "Invalid login attempt.");
        return View(model);
    }

But the userClaims variable is always empty

Questions:

  1. Why is the claims list empty when the claims were just set?
  2. Is there a different type of claim for identity?
  3. Is there a better method for doing this?

UPDATE: I had put a ClaimsTransformer together on some earlier attempts, I can get claims added using that (see the change above in bold in the login controller code) but what do I now do with the ClaimsPrincipal variable identityWithinfoClaims? I can't set User equal to it because User is readonly so how does that object with the claims added get used appropriately?

Georg Patscheider
2#
Georg Patscheider Reply to 2017-11-13 09:56:58Z

To add or transform custom claims, implement and use a custom ClaimsAuthenticationManager. How To: Transform Incoming Claims.

public class ClaimsTransformationModule : ClaimsAuthenticationManager {  
    public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal) {  
        if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated == true) {  
           var identity = (ClaimsIdentity)incomingPrincipal.Identity;
           var user = GetUserData(identity);

           identity.AddClaim(new Claim("fullname", user.GetFullName(user.UserName)));  
           identity.AddClaim(new Claim("avatarUrl", user.AvatarUrl)); 
        }  

        return incomingPrincipal;  
    }  
} 

Here, GetUserData() retrieves the User entity from the DB, given the user name.

Register this transformer in the web.config:

<system.identityModel>
   <identityConfiguration>
      <claimsAuthenticationManager type="MyProject.ClaimsTransformationModule , MyProject, Version=1.0.0.0, Culture=neutral" />
   </identityConfiguration>
</system.identityModel>
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.361343 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO