Search code examples
asp.net-coreasp.net-identity

ASP.NET Core Identity, load user's claims when pulling a user from the database


If your database context inherits from IdentityDbContext<User>, then your context gets properties like UserClaims and RoleClaims. These can be used to get (say) a user's claims as follows...

User jim = await Context.Users.SingleAsync(u => u.Name == "Jim");
List<IdentityUserClaim<string>> claims = await Context
  .UserClaims
  .Where(c => c.UserId == jim.Id)
  .ToListAsync();

However, this seems somewhat clunky. I would have expected to be able to do the following...

User jim = await Context.Users
  .Include(u => u.UserClaims)
  .SingleAsync(u => u.Name == "Jim");

However this doesn't compile. If you change it to include u.Claims then it compiles, but throws an exception... "InvalidOperationException: The expression 'u.Claims' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'"

Now I understand this, in that the User entity doesn't have a Claims navigation property (although I'm not sure where Intellisense picks up the Claims property), but I'm surprised that this isn't something provided when you set up Identity.

Am I missing something here, or do I have to make two database calls to get the user and claims?


Solution

  • Yes,you are right, it doesn't have navigation property by default.

    You could try follow this document to add the navigation property yourself:

    public class ApplicationUser : IdentityUser
    {
        public virtual ICollection<IdentityUserClaim<string>> Claims { get; set; }
    }
    

    Dbcontext:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
    
            modelBuilder.Entity<ApplicationUser>(b =>
            {
                // Each User can have many UserClaims
                b.HasMany(e => e.Claims)
                    .WithOne()
                    .HasForeignKey(uc => uc.UserId)
                    .IsRequired();
            });
        }