How to add claims in ASP.NET Identity
Perhaps the following article can help:
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, "Brock"));
claims.Add(new Claim(ClaimTypes.Email, "brockallen@gmail.com"));
var id = new ClaimsIdentity(claims,DefaultAuthenticationTypes.ApplicationCookie);
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(id);
How to add claims based on the fields from users table in ASP.NET Core MVC?
According to your description, I suggest you could create a custom claim factory which inherits UserClaimsPrincipalFactory
.
Then you could add the additional claims in the override GenerateClaimsAsync method.
More details, you could refer to below codes:
MyUserClaimsPrincipalFactory:
using IdentityTestDemo.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace IdentityTestDemo
{
public class MyUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<IdentityUser>
{
private ApplicationDbContext _appliationDbContext;
public MyUserClaimsPrincipalFactory(
UserManager<IdentityUser> userManager,
IOptions<IdentityOptions> optionsAccessor,ApplicationDbContext applicationDbContext)
: base(userManager, optionsAccessor)
{
_appliationDbContext = applicationDbContext;
}
protected override async Task<ClaimsIdentity> GenerateClaimsAsync(IdentityUser user)
{
//get the data from dbcontext
var Iuser= _appliationDbContext.Users.Where(x => x.EmailConfirmed == true).FirstOrDefault();
var identity = await base.GenerateClaimsAsync(user);
//Get the data from EF core
identity.AddClaim(new Claim("EmailTest", Iuser.Email));
return identity;
}
}
}
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>().AddClaimsPrincipalFactory<MyUserClaimsPrincipalFactory>(); ;
services.AddControllersWithViews();
services.AddRazorPages();
}
In the controller to get the claims:
var result = User.FindFirst("EmailTest").Value;
Result:
Add claims on successful login and retrieve it elsewhere in the application
You must add your claims before login not after. Consider this example:
public async Task<ActionResult> Login(LoginViewModel model,string returnUrl)
{
var user = UserManager.Find(model.Email, model.Password);
if(user!=null)
{
var ident = UserManager.CreateIdentity(user,
DefaultAuthenticationTypes.ApplicationCookie);
ident.AddClaims(new[] {
new Claim("MyClaimName","MyClaimValue"),
new Claim("YetAnotherClaim","YetAnotherValue"),
});
AuthenticationManager.SignIn(
new AuthenticationProperties() { IsPersistent = true },
ident);
return RedirectToLocal(returnUrl);
}
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
Now since we have injected our claims while signing in, we have access to claims wherever we want:
((ClaimsIdentity)User.Identity).FindFirst("MyClaimName");
Also you could add your claims in ApplicationUser.GenerateUserIdentityAsync()
method. By adding your claims in this method you could use SignInManager.PasswordSignInAsync()
method to sign in users without any modification to default Login
action method.
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity .AddClaims(new[] {
new Claim("MyClaimName","MyClaimValue"),
new Claim("YetAnotherClaim","YetAnotherValue"),
});
return userIdentity;
}
}
Add persistent claim with Asp.Net Core Identity
I am not sure when project need to add the external claims. Identity is based on cookie, every request will carry the cookie, so the identity can parse the cookie as the claims. If you want to reload ClaimsIdentity, you need to reuse the method SignInAsync
to regenerate cookie. But there is a global method IClaimsTransformation
can help you add the temporary claim according to different situation.
public class Tanstromer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var claims = new List<Claim> { };
var identity = principal.Identity as ClaimsIdentity;
identity.AddClaim(new Claim("",""));
//you can add some justification here
var userPrinicpal = new ClaimsPrincipal(identity);
return Task.FromResult(principal);
}
}
Add it in ConfigureService
services.AddScoped<IClaimsTransformation, Tanstromer>();
ASP.NET Core custom claims are lost
I finally figured out the culprit myself. It turns out that it did have something to do with the cookie refresh process.
My ApplicationUser
class has a navigation property, which contains all the information that my custom claims transformation class uses to fill up the claims. So all is good there.
Except that I didn't override the UserStore
'sTask<TUser> FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken))
method, which is invoked when the cookie is refreshed. By default, Identity won't load this navigation property, in which case the object is null and the claims will be 'lost' in the process.
So in the end I added an override and added some eager loading, and the problem was resolved.
How to add claims to the HttpContext User on sign in
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>
Related Topics
What Advantages of Extension Methods Have You Found
.Net Core 2.2 Can't Be Selected in Visual Studio Build Framework
Configure JSON.Net to Ignore Datacontract/Datamember Attributes
How to Handle JSON That Returns Both a String and a String Array
Why Does Resharper Want to Use 'Var' for Everything
Custom Header to Httpclient Request
How to Read Attribute Value from Xmlnode in C#
Get Property Name and Type Using Lambda Expression
How to Add Claims in ASP.NET Identity
Why We Need Thread.Memorybarrier()
Differencebetween Getter-Only Auto Properties and Expression Body Properties
"There Was an Error Running the Selected Code Generator" in VS 2013 Scaffolding
Double Buffering When Not Drawing in Onpaint(): Why Doesn't It Work
Hashing Passwords with Md5 or Sha-256 C#