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
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.
https://i.stack.imgur.com/Uk6RQ.jpg
Try this:
[Authorize]
public ActionResult SomeAction()
{
var identity = (ClaimsIdentity)User.Identity;
IEnumerable<Claim> claims = identity.Claims;
...
}
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);
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()
return claim?.Value;
because why not
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();
}
}
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;
You can also do this.
IEnumerable<Claim> claims = ClaimsPrincipal.Current.Claims;
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();
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;
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.
GenerateUserIdentityAsync
was an awesome suggestion, I have totally overlooked it. Thanks a lot Basil.
According to the ControllerBase class, you can get the claims for the user executing the action.
https://i.stack.imgur.com/NNXKa.png
here's how you can do it in 1 line.
var claims = User.Claims.ToList();
var claim = User.Claims.FirstOrDefault(c => c.Type == "claim type here");
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();
}
Success story sharing