I am googling for this thing for quit a long time but still can't get proper answer. I am using identity claim for user authentication and I need some claim values in my _Layout.cshtml page. However I can retrieve custom identity claim values but not built in ones.
Here I set my identity:
var ident = new ClaimsIdentity(
new[] {
// adding following 2 claim just for supporting default antiforgery provider
new Claim(ClaimTypes.NameIdentifier, user.LoginId),
new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string"),
new Claim(ClaimTypes.Name,user.UserName),
new Claim(ClaimTypes.Sid,user.UserId.ToString()),
new Claim("OperationType", user.OperationType.ToString()),
new Claim("ImageLink", user.ImageLink.ToString())
},
DefaultAuthenticationTypes.ApplicationCookie);
var claimsPrincipal = new ClaimsPrincipal(ident);
// Set current principal
Thread.CurrentPrincipal = claimsPrincipal;
and my layout page code:
#using System.Security.Claims;
...........
#{
string userDesignation = ((ClaimsIdentity)User.Identity).FindFirst("OperationType").Value; ;
string userImage = ((ClaimsIdentity)User.Identity).FindFirst("ImageLink").Value; ;
}
I can retrieve my custom claims(ImageLink,OperationType) values but couldn't able to retrieve (Name,Sid) with the same pattern. Some of answers I found that said about Extension methods. Is that only way for retrieve values or have any other way?
Thanks in advance
Please use threading namespace in top of your layout page
#using System.Threading;
and access your claim types as following
#{
string userDesignation = ((ClaimsIdentity)User.Identity).FindFirst("OperationType").Value;
string userImage = ((ClaimsIdentity)User.Identity).FindFirst("ImageLink").Value;
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
// Get the claims values
var id= identity.Claims.Where(c => c.Type == ClaimTypes.Sid)
.Select(c => c.Value).SingleOrDefault();
var s = id;
//so on.......
}
But #Erik Philips is right. You should use those logic as partial.
You can create a LayoutController with a method you call from your layout with html.RenderPartial() (from comment below #Erik Philips).
TextInfo myTI = new CultureInfo("en-US", false).TextInfo;
var claimsIdentity = HttpContext.Current.User.Identity as System.Security.Claims.ClaimsIdentity;
var displayNameClaim = (claimsIdentity == null) ? null : claimsIdentity.Claims.SingleOrDefault(x => x.Type == ApplicationUser.DisplayNameClaimType);
var nameToDisplay = (displayNameClaim == null) ? HttpContext.Current.User.Identity.Name : displayNameClaim.Value;
var nameToDisplayTitle = myTI.ToTitleCase(nameToDisplay);
In the view, the name value is injected into a <span class="NameDisplay"></span>.
$(".NameDisplay").html(#Html.Raw("\"" + nameToDisplayTitle + "\""));
In IdentityModels.cs, I define the following field:
public class ApplicationUser : IdentityUser
{
public const string DisplayNameClaimType = "FirstName";
[Display(Name = "First Name")]
public string FirstName { get; set; }
//etc.
}
and define this claim:
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(DisplayNameClaimType, FirstName));
return userIdentity;
}
Related
I need to check RoleSecurityStamp in .net core authentication based on JWT.
I have populated the token claims like this:
public IEnumerable<Claim> CustomClaims(LoginResult user)
{
var securityStampClaimType = new ClaimsIdentityOptions().SecurityStampClaimType;
var rolesecurityStampClaimType = new ClaimsIdentityOptions().SecurityStampClaimType;
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name,user.Username),
new Claim(ClaimTypes.NameIdentifier,user.Id.ToString()),
new Claim(securityStampClaimType,user.UserSecurityStamp.ToString()),
new Claim(rolesecurityStampClaimType,user.RoleSecurityStamp.ToString())
};
return claims;
}
I need to check it in OnTokenValidated:
OnTokenValidated = async context =>
{
var userService = context.HttpContext.RequestServices.GetRequiredService<IUseServiceDapper>();
var claimsIdentity = context.Principal.Identity as ClaimsIdentity;
var securityStamp =Guid.Parse(claimsIdentity.FindFirstValue(new ClaimsIdentityOptions().SecurityStampClaimType));
var userId = claimsIdentity.GetUserId<int>();
var userSecurityInfo = await userService.UserSecurityInfo(userId);
//if (claimsIdentity.Claims?.Any != true)
// context.Fail("Token Has No Claim");
if (securityStamp == null)
context.Fail("Token Has No SecurityStamp");
if (userSecurityInfo.Result.IsActive == false)
context.Fail("User Not Active");
if (userSecurityInfo.Result.UserSecurityStamp != securityStamp)
context.Fail("Security Stamp Not Matched");
},
I have found the UserSecurityStamp by using the following code:
var securityStamp = Guid.Parse(claimsIdentity.FindFirstValue(new ClaimsIdentityOptions().SecurityStampClaimType));
but I cannot find the RoleSecurityStamp.
How Can I Find Role Security Stamp and Check It ????
You are giving the same claim type to your UserSecurityStamp and RoleSecurityStamp which is
ClaimsIdentityOptions().SecurityStampClaimType;
which basically defaults to : "AspNet.Identity.SecurityStamp"
so to be able to find your RoleSecurityStamp you need to give it a different claim type and you FindFirstValue that type instead, or you can instead try FindAll() which will return a list that contains the UserSecurityStamp and RoleSecurityStamp.
Edit:
Same claim type example:
var securityStampsList = claimsIdentity.FindAll(new ClaimsIdentityOptions().SecurityStampClaimType).ToList();
var securityStamp = Guid.Parse(securityStampsList[0].Value);
var roleSecurityStamp = Guid.Parse(securityStampsList[1].Value);
I need to store additional user properties per user when using windows authentication and based off AD groups. What is the easiest way to do this?
Here is my code to check that a user belongs to an AD Group, i'd like this to run per user that logs on:
var domain = HttpContext.Current.User.Identity.Name.Split('\\')[0];
using (var ctx = new PrincipalContext(ContextType.Domain, domain))
using (var user = UserPrincipal.FindByIdentity(ctx, HttpContext.Current.User.Identity.Name))
{
if (user != null)
{
var groups = user.GetGroups()
.Select(x => x.SamAccountName);
if (groups.Contains("Special User"))
User.IsSpecial = true;
//something like this would be ideal
Then I would like to be able to check the property throughout the app:
public ActionResult Index()
{
if(User.IsSpecial)
{
...
}
}
Basically I need to check the AD groups of the user once to set the property and then use the property subsequently to alter page behaviour.
EDIT:
In line with #Matthijs suggestion below I had a look at Claims authentication but I can't get my claims to persist between requests. Any suggestions on how to do this? I add the claim in global.asax and read the value in my controllers.
protected void Application_AuthorizeRequest()
{
var claimsPrincipal = User as ClaimsPrincipal;
var claimsIdentity = User.Identity as ClaimsIdentity;
if (!claimsPrincipal.Claims.Where(x => x.Type == "Client").Any())
{
var domain = User.Identity.Name.Split('\\')[0];
using (var ctx = new PrincipalContext(ContextType.Domain, domain))
using (var user = UserPrincipal.FindByIdentity(ctx, HttpContext.Current.User.Identity.Name))
{
if (user != null)
{
var groups = user.GetGroups()
.Select(x => x.SamAccountName);
if (groups.Contains("Special User")
{
claimsIdentity.AddClaim(new Claim("IsSpecial", "Yes"));
}
Controller:
var claimsPrincipal = User as ClaimsPrincipal;
var isSpecial = claimsPrincipal.Claims.Where(x => x.Type == "IsSpecial").First().Value;
You could use Claims for that. The .NET Core documentation provides more details about the usage of claims. It is possible to create your own claims, like IsSpecial.
More information about claims can be found in this answer on StackOverflow.
Long story short, I use Identity and in my solution I created a custom account settings page which works fine and dandy. The problem is that I have the users FirstName and LastName in the _Layout.cshtml. The name is set by a custom helper method I have:
public static MvcHtmlString GetUsersFirstAndLastName(this HtmlHelper helper)
{
string fullName = HttpContext.Current?.User?.Identity?.Name ?? string.Empty;
var userIdentity = (ClaimsPrincipal)Thread.CurrentPrincipal;
var nameClaim = identity?.FindFirst("fullname");
if (nameClaim != null)
{
fullName = nameClaim.Value;
}
return MvcHtmlString.Create(fullName);
}
This method works great, until a user goes to their profile and updates their name. If they change their name from George to Bob then when they go around on my website this method still pulls their name as George until they log out and log back in.
So what I did to fix that was when they update their name in the account settings I added some code to remove their old fullName claim, and add the new one, like this:
var identity = User.Identity as ClaimsIdentity;
// check for existing claim and remove it
var currentClaim = identity.FindFirst("fullName");
if (currentClaim != null)
identity.RemoveClaim(existingClaim);
// add new claim
var fullName = user.FirstName + " " + user.LastName;
identity.AddClaim(new Claim("fullName", fullName));
With this bit of code the _Layout view now updates the name (in our previous example George will now change to Bob). However, the moment the click out of that view to another place on the website or the moment they refresh the page it changes right back to George.
Still being a bit new to identity I'm a bit puzzled why this new updated claim does not work after they click around to a different page or refresh. Any help is appreciated. :)
When adding the new claim you also needed to do this:
var authenticationManager = HttpContext.GetOwinContext().Authentication;
authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = true });
So the new full code block is:
public static MvcHtmlString GetUsersFirstAndLastName(this HtmlHelper helper)
{
string fullName = HttpContext.Current?.User?.Identity?.Name ?? string.Empty;
var userIdentity = (ClaimsPrincipal)Thread.CurrentPrincipal;
var nameClaim = identity?.FindFirst("fullname");
var authenticationManager = HttpContext.GetOwinContext().Authentication;
authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = true });
if (nameClaim != null)
{
fullName = nameClaim.Value;
}
return MvcHtmlString.Create(fullName);
}
I am using Asp.net identity for Login,Register,Forgot Password etc and source code is taken from this below link:
http://www.asp.net/mvc/overview/security/create-an-aspnet-mvc-5-web-app-with-email-confirmation-and-password-reset
http://www.asp.net/identity/overview/features-api/account-confirmation-and-password-recovery-with-aspnet-identity.
Now i have 1 table that is UserMaster and during registration i am asking for this following fields:
FullName,EmailId,Password,ContactNumber,Gender.
My UserMaster Contains this following fields:Id,FullName,EmailId,ContactNumber,Gender
Now when user will submit registration form this FullName,EmailId,ContactNumber,Gender will be saved in UserMaster along with the Email,Password will be saved in AspnetUser.
My Register Method is same as provided in above 2 links.
Here you might notice that there is no relationship between my UserMaster and AspnetUser so during login when user will enter his email id to login i will use this method await SignInManager.PasswordSignInAsync to verify user and if this method returns success then what i will do is use this email id and check this email in my UserMaster and where match will be found i will fetch that UserId from UserMaster and store it in session and use thorugh out my application in my login method like below:
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
using (var context = new MyEntities())
{
var fetchUSerId = context.UserMaster.Where(t => t.Email == model.Email).Select(t=>t.UserId).SingleOrDefault();
Session["UserId"] = fetchUSerId;
}
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
}
I am talking about this in my login method:
case SignInStatus.Success:
using (var context = new MyEntities())
{
var fetchUSerId = context.UserMaster.Where(t => t.Email == model.Email).Select(t=>t.UserId).SingleOrDefault();
Session["UserId"] = fetchUSerId;
}
Is this an appropriate way or still a better way and i want to store entire user object instead of just storing User Id.
So can anybody tell me how to do this with aspnet identity??
Since you are using Asp.Net Identity, you want to store session related stuff as claims. This is very easy to extend with customised claims.
As an aside, I think you'd be better off simple extending ApplicationUser to hold the additional data, as detailed here.
That said, here is a complete example of how to add custom claim types to your application.
Step 1 - Define one or more custom claim types to hold your additional information
public static class CustomClaimTypes
{
public const string MasterFullName = "http://schemas.xmlsoap.org/ws/2014/03/mystuff/claims/masterfullname";
public const string MasterUserId = "http://schemas.xmlsoap.org/ws/2014/03/mystuff/claims/masteruserid";
}
A claim type is just a unique string that identifies the specific claim. Here we are just using a similar format as the built in claim types.
Step 2 - During the sign in process, set values for the custom claim types
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
//Fetch data from the UserMaster table
var userdata = GetdatafromUserMaster();
//Using the UserMaster data, set our custom claim types
identity.AddClaim(new Claim(CustomClaimTypes.MasterUserId, userdata.UserId));
identity.AddClaim(new Claim(CustomClaimTypes.MasterFullName, userdata.FullName));
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
Note: we are using custom claim types so that we preserve the existing NameIdentifier and Name claims, and can therefore easily access identity information from both Asp.Net Identity and our custom UserMaster table.
Step 3 - Add extension method(s) to IIdentity so we can easily access our custom claim data
public static class IdentityExtensions
{
public static string GetMasterUserId(this IIdentity identity)
{
if (identity == null)
return null;
return (identity as ClaimsIdentity).FirstOrNull(CustomClaimTypes.MasterUserId);
}
public static string GetMasterFullName(this IIdentity identity)
{
if (identity == null)
return null;
return (identity as ClaimsIdentity).FirstOrNull(CustomClaimTypes.MasterFullName);
}
internal static string FirstOrNull(this ClaimsIdentity identity, string claimType)
{
var val = identity.FindFirst(claimType);
return val == null ? null : val.Value;
}
}
Nothing fancy here. We just cast the IIdentity as a ClaimsIdentity and then return the value of either the first claim of the given CustomClaimType that we find, or we return null if a claim doesn't exist.
Step 4 - Now we can access our custom claim data in views and/or controllers really easily. Say you wanted to use the full name from your UserMaster table instead of the ApplicationUser? You can now do this:
<ul class="nav navbar-nav navbar-right">
<li>
#Html.ActionLink("Hello " + User.Identity.GetMasterFullName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
</li>
<li>Log off</li>
</ul>
You can also do the same thing from within a Controller.
You can add as:
var listClaims=new[] { new Claims(ClaimsType.SerialNumber,Id), new Claims(ClaimsType.Name,FullName), new Claims(ClaimsType.HomePhone,ContactNumber), new Claims(ClaimsType.Gender,Gender)};
var oAuthIdentity=new ClaimsIdentity(listClaims, otherparameter ...);
For more details you can check System.Secutity.Claims.ClaimTypes
you may do this:
var fetchUser = context.UserMaster.Where(t => t.Email == model.Email).SingleOrDefault();
if (null == fetchUser)
throw new Exception("Not found");
Session["User"] = fetchUser;
I am struggling a bit with Asp.net Identity and updating a user. When I run the code below succeed is false and the error message is that the user with username exists. Which is - of course - obvious because you are updating a user, not creating a new one.
I have tried to remove the username without much success, I was then told that the Name (I believe it meant Username) could not be empty.
Snip of code below.
public async Task<ActionResult> Edit(RegisterViewModel model)
{
var user = new User()
{
UserName = model.UserName, FirstName = model.FirstName, LastName = model.LastName, Email = model.EmailAddress,
ApplicationId = Utilities.ApplicationUtilities.GetApplicationId()
};
var userContext = new ApplicationDbContext();
var userStore = new UserStore<User>(userContext);
var userManager = new UserManager<User>(userStore);
var result = await userManager.UpdateAsync(user);
if (result.Succeeded)
{
var selectedRole = model.SelectedRole;
if (!userManager.IsInRole(user.Id, selectedRole.Id))
{
// We are removing the user from the old role. He / she cannot have two or more roles
userManager.RemoveFromRole(user.Id, model.OldRole);
// Now we are adding the user to the new role
userManager.AddToRole(user.Id, selectedRole.Id);
userManager.Update(user);
}
userContext.SaveChanges();
// await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "UserManager");
}
The solution based on the input from Jonesy became something like this:
/*
* Some more information /Just in case someone else does the same
* mistakes I did...
*/
model.OldRole = "User"; // Name of old role - not ID of old role
model.SelectedRoleId = "Administrator"; // Name of new role, not ID of new role
// This test is here just to check if the model is valid or not
// By adding this part, you can check what is possibly wrong with your model
if (!ModelState.IsValid)
{
var errors = ModelState
.Where(x => x.Value.Errors.Count > 0)
.Select(x => new {x.Key, x.Value.Errors})
.ToArray();
}
// Creating the ApplicationDbContext object
var userContext = new ApplicationDbContext();
// Getting the list of users (I tried using Find here, but got errors)
var userList = userContext.Users.ToList();
// Decided to use First or Default. You also have to use double
// equal-characters(=) otherwise you will get errors
var user = userList.FirstOrDefault(u => u.UserName == model.UserName);
// Checking that we really found the user to update
if (user != null)
{
// populate the user object
user.UserId = model.UserId;
user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.Email = model.EmailAddress;
}
// creating the UserStore object
var userStore = new UserStore<User>(userContext);
// ... and the userManager object
var userManager = new UserManager<User>(userStore);
// Do the update - I believe this is on the userManager-object
// and not in the database
var result = await userManager.UpdateAsync(user);
// If we get an error, we return to list of Users
// (You should log the error and also return the user to the form)
if (!result.Succeeded) return RedirectToAction("Index", "UserManager");
// Do the actual update in the database
userContext.SaveChanges();
// If the old role and the selected role is the same, we don't
// have to update
if (model.OldRole == model.SelectedRoleId) return RedirectToAction("Index", "UserManager");
// Get the selected role (sort of not needed, but here for clarity)
string selectedRole = model.SelectedRoleId;
// We are removing the user from the old role.
// In our application a user cannot have two or more roles
userManager.RemoveFromRole<User, string>(user.UserId, model.OldRole);
// Now we are adding the user to the new role
userManager.AddToRole<User, string>(user.UserId, selectedRole);
// We are updating the userManager-object
userManager.Update(user);
// And storing the information in the database
userContext.SaveChanges();
// Returning the user to the list of users
return RedirectToAction("Index", "UserManager");
use your dbContext to pull the user to update, instead of creating a new one:
var user = userContext.Find(model.UserName);
or you may need
var user = userContext.FirstOrDefault(u => u.UserName = model.UserName && u.Email = model.EmailAddress);
if(user != null)
{
//update user
}
this is an old one but just wanted to post my solution to the same update issue
var user = UserManager.FindByEmail(model.Email);
user.Address = model.Address;
user.City = model.City;
user.State = model.State;
var result = await UserManager.UpdateAsync(user);
you can also manage roles
user.Roles.Add(Role);
user.Roles.Remove(Role);