MVC 5 Access Claims Identity User Data

asp.netasp.net MvcAuthenticationasp.net Mvc-5Claims Based-Identity

asp.net Problem Overview


I am developing an MVC 5 web application using Entity Framework 5 Database First approach. I am using OWIN for the authentication of Users. Below shows my Login method within my Account Controller.

public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var user = _AccountService.VerifyPassword(model.UserName, model.Password, false);
        if (user != null)
        {
            var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, model.UserName), }, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);

            identity.AddClaim(new Claim(ClaimTypes.Role, "guest"));
            identity.AddClaim(new Claim(ClaimTypes.GivenName, "A Person"));
            identity.AddClaim(new Claim(ClaimTypes.Sid, user.userID)); //OK to store userID here?

            AuthenticationManager.SignIn(new AuthenticationProperties
            {
                IsPersistent = model.RememberMe
            }, identity);

            return RedirectToAction("Index", "MyDashboard");
        }
        else
        {
            ModelState.AddModelError("", "Invalid username or password.");
        }
    }
    // If we got this far, something failed, redisplay form
    return View(model);
}

As you can see I'm creating a ClaimsIdentity and adding several claims to it, then passing it to OWIN using the AuthenticationManager to perform the sign in.

The problem I am having is that I'm not sure how to access the claims in the rest of my application, either in Controllers or in Razor Views.

I had tried the approach listed in this tutorial

http://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/

For example, I tried this in my Controller code in an attempt to get access to the values passed into the Claims, however, the user.Claims is equal to null

var ctx = HttpContext.GetOwinContext();
ClaimsPrincipal user = ctx.Authentication.User;
IEnumerable<Claim> claims = user.Claims;

Perhaps I am missing something here.

UPDATE

Based on Darin's answer, I added his code but still I fail to see access to the Claims. Please see screenshot below showing what I see when hovered over identity.Claims.

enter image description here

asp.net Solutions


Solution 1 - asp.net

Try this:

[Authorize]
public ActionResult SomeAction()
{
    var identity = (ClaimsIdentity)User.Identity;
    IEnumerable<Claim> claims = identity.Claims;
    ...
}

Solution 2 - asp.net

You can also do this:

//Get the current claims principal
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
var claims = identity.Claims;

Update

To provide further explanation as per comments.

If you are creating users within your system as follows:

UserManager<applicationuser> userManager = new UserManager<applicationuser>(new UserStore<applicationuser>(new SecurityContext()));
ClaimsIdentity identity = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);

You should automatically have some Claims populated relating to you Identity.

To add customized claims after a user authenticates you can do this as follows:

var user = userManager.Find(userName, password);
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));

The claims can be read back out as Darin has answered above or as I have.

The claims are persisted when you call below passing the identity in:

AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = persistCookie }, identity);

Solution 3 - asp.net

I make my own extended class to see what I need, so when I need into my controller or my View, I only add the using to my namespace something like this:

public static class UserExtended
{
    public static string GetFullName(this IPrincipal user)
    {
        var claim = ((ClaimsIdentity)user.Identity).FindFirst(ClaimTypes.Name);
        return claim == null ? null : claim.Value;
    }
    public static string GetAddress(this IPrincipal user)
    {
        var claim = ((ClaimsIdentity)user.Identity).FindFirst(ClaimTypes.StreetAddress);
        return claim == null ? null : claim.Value;
    }
    public ....
    {
      .....
    }
}

In my controller:

using XXX.CodeHelpers.Extended;

var claimAddress = User.GetAddress();

In my razor:

@using DinexWebSeller.CodeHelpers.Extended;

@User.GetFullName()

Solution 4 - asp.net

This is an alternative if you don't want to use claims all the time. Take a look at this tutorial by Ben Foster.

public class AppUser : ClaimsPrincipal
{
    public AppUser(ClaimsPrincipal principal)
        : base(principal)
    {
    }

    public string Name
    {
        get
        {
            return this.FindFirst(ClaimTypes.Name).Value;
        } 
    }

}

Then you can add a base controller.

public abstract class AppController : Controller
{       
    public AppUser CurrentUser
    {
        get
        {
            return new AppUser(this.User as ClaimsPrincipal);
        }
    }
}

In you controller, you would do:

public class HomeController : AppController
{
    public ActionResult Index()
    {
        ViewBag.Name = CurrentUser.Name;
        return View();
    }
}

Solution 5 - asp.net

To further touch on Darin's answer, you can get to your specific claims by using the FindFirst method:

var identity = (ClaimsIdentity)User.Identity;
var role = identity.FindFirst(ClaimTypes.Role).Value;

Solution 6 - asp.net

You can also do this.

IEnumerable<Claim> claims = ClaimsPrincipal.Current.Claims;

Solution 7 - asp.net

Remember that in order to query the IEnumerable you need to reference system.linq.
It will give you the extension object needed to do:

CaimsList.FirstOrDefault(x=>x.Type =="variableName").toString();

Solution 8 - asp.net

shortest and simplified version of @Rosdi Kasim'd answer is

string claimvalue = ((System.Security.Claims.ClaimsIdentity)User.Identity).
    FindFirst("claimname").Value;

Claimname is the claim you want to retrieve i.e if you are looking for "StreedAddress" claim then the above answer will be like this

string claimvalue = ((System.Security.Claims.ClaimsIdentity)User.Identity).
    FindFirst("StreedAddress").Value;

Solution 9 - asp.net

Request.GetOwinContext().Authentication.User.Claims

However it is better to add the claims inside the "GenerateUserIdentityAsync" method, especially if regenerateIdentity in the Startup.Auth.cs is enabled.

Solution 10 - asp.net

According to the ControllerBase class, you can get the claims for the user executing the action.

enter image description here

here's how you can do it in 1 line.

var claims = User.Claims.ToList();

Solution 11 - asp.net

var claim = User.Claims.FirstOrDefault(c => c.Type == "claim type here");

Solution 12 - asp.net

I used it like that in my base controller. Just sharing for ready to use.

    public string GetCurrentUserEmail() {
        var identity = (ClaimsIdentity)User.Identity;
        IEnumerable<Claim> claims = identity.Claims;
        var email = claims.Where(c => c.Type == ClaimTypes.Email).ToList();
        return email[0].Value.ToString();
    }

    public string GetCurrentUserRole()
    {
        var identity = (ClaimsIdentity)User.Identity;
        IEnumerable<Claim> claims = identity.Claims;
        var role = claims.Where(c => c.Type == ClaimTypes.Role).ToList();
        return role[0].Value.ToString();
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiontcodeView Question on Stackoverflow
Solution 1 - asp.netDarin DimitrovView Answer on Stackoverflow
Solution 2 - asp.nethutchonoidView Answer on Stackoverflow
Solution 3 - asp.netJesus PadillaView Answer on Stackoverflow
Solution 4 - asp.netQuentinView Answer on Stackoverflow
Solution 5 - asp.netEric BridgesView Answer on Stackoverflow
Solution 6 - asp.netangularsenView Answer on Stackoverflow
Solution 7 - asp.netMarc Sedote SossouView Answer on Stackoverflow
Solution 8 - asp.netnoman zafarView Answer on Stackoverflow
Solution 9 - asp.netBassel BanboukView Answer on Stackoverflow
Solution 10 - asp.netconterioView Answer on Stackoverflow
Solution 11 - asp.netFelipe DevezaView Answer on Stackoverflow
Solution 12 - asp.netB MView Answer on Stackoverflow