In my aspnet core MVC app if I retrieve a user using an injected UserManager then the following returns true:
await _userManager.IsInRoleAsync( user, "Administrator" );
However, whenever I check User (ClaimsPrincipal) in a view like so, the claim is missing (returns false):
User.IsInRole( "Administrator" );
This seems inconsistent to me.
Do I have to manually set Role claims myself somewhere? I imagined that would come for free and that a custom UserClaimsPrincipalFactory would be for app-specific Claims as opposed to Roles (which come out-of-the-box with MVC).
What am I missing?
It's a known issue in the version of 2.1 and has been fixed in 2.2 preview-1 .
In asp.net core 2.1, AddDefaultIdentity is used and the injection becomes to
services.AddDefaultIdentity<IdentityUser>()
.AddRoles<IdentityRole>()
,will not make Roles enabled by default and it always return false for User.IsInRole.
To walk around it , instead of using the new AddDefaultIdentity<TUser>() to configure Identity , simply use the old-style api :
services.AddIdentity<IdentityUser, IdentityRole>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddDefaultUI()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
Another way is that you could replace the UserClaimsPrincipal factory with the one that's role aware.Add below code in ConfigureService and refer to UserRoles in DefaultIdentity
services.AddScoped<IUserClaimsPrincipalFactory<IdentityUser>, UserClaimsPrincipalFactory<IdentityUser, IdentityRole>>();
Related
I'm new in asp.net and I'm watching a course to learn it.
In this course httpContextAccessor was used to get the userName and it's Role.
But I can't find the reason behind using it. I can call the global "User" and get the data without using httpContext like the below.
var role = User.FindFirstValue(ClaimTypes.Role);
var name = User.Identity.Name;
instead of
_LoginUserId = httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
_Userrole =httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.Role);
Why i have to use httpContextAccessor in Asp.Net to get user name and role?
the main reason behind HttpContextAccessor is to avail httpcontext inside service as User is connected to http context and only available in the web project unless assemblies are added explicitly in libraries, check this link for more details.
I am having a difficult time understanding how to add custom claims when using Windows authentication in a .Net MVC app.
The challenge here is to populate the users's identity with custom claims from the database on login, so as to avoid making a db call every time I want to check a custom authorization attribute. But the use of Windows auth complicates things for me, as there's no login method in which to put the code that populates the roles.
Is there a method to override, or some other way to hook into the Windows auth login process?
In .NET Core 2.0 you should use IClaimsTransformation.
For example:
public class CustomClaimsTransformer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
((ClaimsIdentity)principal.Identity)
.AddClaim(new Claim(claim.Name, claim.Value)); //your values
return Task.FromResult(principal);
}
}
And add this code to Startup.cs
...
services.AddMvc();
services.AddScoped<IClaimsTransformation,CustomClaimsTransformer>(); // Add this
I don't know how to do this in ASP.NET MVC :/.
This is my first answer here :).
I am trying to move away from WebForms and learn MVC, specifically using the new ASP.NET Identity model. However, I cant seem to find any formal documentation from Microsoft, that demonstrates how to create a claims object, and store it in a database for a authenticated user.
My site, needs to do the following:
Authentication a user - TICK
Create a Claim, and store user information in it, so that I can use it throughout the session - NO TICK
Pull back the users roles from the new ASP.NET Roles table - NOT TICK
Can anyone shed any light on how this can be achieve?
Honestly, I'm still learning the ropes with Identity, myself. Admittedly, the Microsoft provided documentation could be better, but I've never found any of their documentation all that helpful. The best stuff always comes from the community, and unfortunately, Identity is still so new that the community has had time to really flesh it out yet.
That said, here's what I know, with the understanding that there may be better ways that I'm simply not aware of, yet.
Claims
Your UserManager has three methods of significance: GetClaimsAsync, AddClaimAsync and RemoveClaimAsync.
To get all claims for a user:
var claims = await UserManager.GetClaimsAsync(userId);
You can get the current user's id with:
var userId = User.Identity.GetUserId();
Once you have the claims, to pull out a specific one:
var someClaim = claims.FirstOrDefault(c => c.Type == "SomeClaimType");
Where "SomeClaimType" is the name of the claim as it was added. In some scenarios this might be a fully qualified URN, or it may just be a simple string. If it's not something you personally added, the best thing to do is just inspect the claims variable during a debug session to see what you actually have there.
Also, since the list of claims is a queryable, you can pretty much do whatever LINQ query you want on it, Where, Count, etc.
To add a new claim:
await UserManager.AddClaimAsync(userId, new Claim("SomeClaimType", claimValue));
And to remove a claim:
await UserManager.RemoveClaimAsync(userId, someClaim);
Roles
Roles work in a similar way. To get all roles for a user:
var roles = await UserManager.GetRolesAsync(userId);
To see if a user is in a particular role:
var hasRole = await UserManager.IsInRoleAsync(userId, "SomeRole");
To add a user to a particular role:
await UserManager.AddToRoleAsync(userId, "SomeRole");
And to remove:
await UserManager.RemoveFromRoleAsync(userId, "SomeRole");
Adding the roles in the first place is a bit different; you have to create an instance of RoleStore.
var roleStore = new RoleStore<IdentityRole>(context);
Then, you can use that to manage all roles. For example, to create a new role:
await roleStore.CreateAsync(new IdentityRole("RoleName"));
To remove:
var identityRole = await roleStore.FindByNameAsync("RoleName");
await roleStore.DeleteAsync(identityRole);
Getting all roles, is not possible with the Identity-specific API at this time, but you can always fall back to querying with Entity Framework directly:
var allRoles = context.Roles.OrderBy(o => o.Name);
Regarding Asp.Net Identity, I would strongly recommend Brock Allen's implementation, called 'Identity Reboot'. Identity Reboot basically is a set of extensions to the ASP.NET Identity. It was inspired due to frustrations with the ASP.NET Identity implementation.
You can read an introductory article here. You can download source code and samples from github here.
You can install it using nuget:
www.nuget.org/packages/BrockAllen.IdentityReboot/
www.nuget.org/packages/BrockAllen.IdentityReboot.Ef/ (for entity framework)
I'm using ASP.Net Identity with ADFS 2.0 (I think).
Users log in at a separate server, come back to me, I check the ClaimsPrincipal and pull out the userID claim, then use that ID to retrieve the user.
So I'm only using ADFS/claims-based auth to get the user object; after that, I have things like usergroups and roles, but they are custom objects and I manage them in the application rather than using ADFS to manage them.
What I want to know is: How hard is it to use my custom database roles with the out-of-the-box role stuff? Specifically, I want to be able to use the Role("RoleName") attribute on controllers, and wrap some UI elements in User.IsInRole("RoleName") on the views to control user access.
What do I have to do to wire this up?
I'm not aware of any Role attribute. Do you mean Authorize("RoleName") attribute?
Adding a role claim that is compatible with IPrincipal.IsInRole and AuthorizeAttribute as a consequence is very easy. Just add a claim with the type ClaimTypes.Role
//when creating a new identity
var identity = new ClaimsIdentity(new Claim[] {
new Claim(ClaimTypes.Role, "MyRole1"),
new Claim(ClaimTypes.Role, "MyRole2")
});
//add a claim to an identity
identity.AddClaim(new Claim(ClaimTypes.Role, "MyRole3"));
Then in your controller, add the AuthorizeAttribute
Authorize("MyRole1")
I am developing an MVC 4 Application to be hosted in Azure and want to use their ACS service for authentication. Once the user is authenticated I will use the resulting claim details to correlate to my local records. Subsequent to that, I would like to extend the claimset to include additional claims that represent local authorizations which my application would use for authorization decisions. I assume I need to replace the Principle but I'm not sure where/when to do this in MVC and want to avoid breaking any of the authentication plumbing which would normally be used throughout the life of the session. Can anyone shed some light on this?
The extensibility point in WIF for enriching the claimset is the ClaimsAuthenticationManager
From the docs:
The claims authentication manager provides an extensibility point in
the RP processing pipeline that you can use to filter, modify, or
inject new claims into the set of claims presented by an
IClaimsPrincipal before the RP application is called.
You can also add rules in ACS to enrich the token with the claims you need.
In addition to what #Eugenio Pace has said, it's worth noting that you can just add and remove claims to and from the IClaimsPrincipal:
public static void UpdateClaims(IClaimsIdentity identity)
{
identity.Claims.Remove(identity.Claims.SingleOrDefault(x => x.ClaimType == ClaimTypes.Name));
identity.Claims.Remove(identity.Claims.SingleOrDefault(x => x.ClaimType == ClaimTypes.Email));
identity.Claims.Add(new Claim(ClaimTypes.Name, "Steve Smith"));
identity.Claims.Add(new Claim(ClaimTypes.Email, "steve#smith.com"));
}
UpdateClaims(User.Identity as IClaimsIdentity);
Claims added can either be one of the types enumerated in ClaimTypes, or a custom string of your own devising. You can add multiple claims of type ClaimTypes.Role - I'm not sure about the other types.
From the ClaimsCollection docs:
Represents a collection of claims associated with a single subject.
Adding a Claim to a ClaimCollection implicitly associates that Claim
with the subject associated with the collection by calling the
SetSubject method.
Removing a Claim from a ClaimCollection implicitly removes this
association by also calling the SetSubject method.
http://msdn.microsoft.com/en-us/library/microsoft.identitymodel.claims.claimcollection.aspx
Update
For .Net 4.5, the identity class and the method for updating claims have changed, as well as the namespace:
using System.IdentityModel;
using System.Security.Claims;
public static void UpdateClaims(Member member, ClaimsIdentity identity)
{
identity.RemoveClaim(identity.Claims.SingleOrDefault(x => x.Type == ClaimTypes.Name));
identity.RemoveClaim(identity.Claims.SingleOrDefault(x => x.Type == ClaimTypes.Email));
identity.AddClaim(new Claim(ClaimTypes.Name, "Steve Smith"));
identity.AddClaim(new Claim(ClaimTypes.Email, "steve#smith.com"));
}
UpdateClaims(User.Identity as ClaimsIdentity);
http://msdn.microsoft.com/en-us/library/system.security.claims.claimsidentity.aspx