nurdyguy
nurdyguy

Reputation: 2945

Identity Roles not being populated

I have a simple sandbox project I'm using to get to better understand how .net Core Identity works and I've come across a bit of an inconsistency that I hope someone can explain. This project is using Entity Framework.

I used this awesome article to help me set up the project, https://medium.com/@goodealsnow/asp-net-core-identity-3-0-6018fc151b4#.2env44446 and my User class is as follows.

public class User : IdentityUser<int>
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string TempPassword { get; set; }
}

I seeded the db with three users and three roles, one user for each role, "Owner", "Admin", and "User". I added some policies for my actions,

auth.AddPolicy("Owner", policy =>
{
    policy.RequireAuthenticatedUser();
    policy.RequireRole("Owner");
 });

 auth.AddPolicy("Admin", policy =>
 {
     policy.RequireAuthenticatedUser();
     policy.RequireRole("Admin", "Owner");
 });

 auth.AddPolicy("User", policy =>
 {
     policy.RequireAuthenticatedUser();
 });   

so my attributes like [Authorize("Admin")] work great. I even added some principal extensions as so

public static class PrincipalExtensions
{
    public static bool IsOwner(this ClaimsPrincipal principal)
    {
        return principal.IsInRole("Owner");
    }

    public static bool IsAdmin(this ClaimsPrincipal principal)
    {
        return principal.IsInRole("Admin") || principal.IsInRole("Owner");
    }

    public static bool IsUser(this ClaimsPrincipal principal)
    {
        return principal.Identity.IsAuthenticated;
    }
}

so I can do if(User.IsAdmin()) and this works perfectly as well.

Here is where it gets weird...

If I step through the following code I get confusing results.

var user = await _userManager.GetUserAsync(User);            
var userRoles = await _userManager.GetRolesAsync(user);
await _userManager.AddToRoleAsync(user, "Owner");

The first line gets me a User object for the principal. On that object there is a collection of his Roles, user.Roles, but it will show empty (Count = 0) even though the user does have roles.

The second line gets the Roles for the user and it populates correctly.

The third line adds the "Owner" role to the user and it works correctly (the db is updated) but also, the local variable user suddenly now has that role in user.Roles! Note, none of the user's other roles will show up, just that one.

So I have basically two questions: 1. Why doesn't the user object have the user.Roles populated to begin with? 2. Why is it suddenly synced after I add a role?

Any help is appreciated.

Upvotes: 1

Views: 914

Answers (1)

Polynomial
Polynomial

Reputation: 3706

Your Roles collection isn't populated after calling GetUserAsync() as the EntityFramework Identity UserStore doesn't request the information. It's doing the equivalent of you accessing the user data directly through your DbContext and without any calls to Include().

Right now EF Core does not support lazy loading, and therefore the user.Roles navigation property isn't automatically populated. And yes, this makes the behaviour somewhat disingenuous at the moment.

In your calls to GetRolesAsync() and AddToRoleAsync() the data is being explicitly populated for you, as you are operating on the roles directly.

Upvotes: 1

Related Questions