ASP.net Identity - How does UserManager<TUser> Have Access To Roles?

3.9k Views Asked by At

... and we're only inside Microsoft.AspNet.Identity. (We're not even looking at the base implementation at Microsoft.AspNet.Identity.EntityFramework.)

The UserManager class only takes in an IUserStore<TUser> at constructor. It does not have an IUserRoleStore<TUserRole> which I imagine would need to be accessed to determine whether UserManager.IsInRoleAsync(string, string) or not.

I'm thinking UserStore's implementation would have an IsInRoleAsync(string, string) function as well (then it would all make sense), but it does not.

Another strange thing - how can UserManager be able to perform password setting and resetting if all it knows inside its implementation is that we're dealing with an IUser - with only string Id and string UserName as properties?

1

There are 1 best solutions below

1
On

Alright, after much digging and lucky discovery - it turns out that Microsoft.AspNet.Identity.Core comes with a few other interfaces, in particular, IUserRoleStore<TUser> and IUserPasswordStore<TUser> which both "inherit"(implement) IUserStore<TUser>.

So if we wanted role management capabilities, we implement IUserRoleStore<TUser>:

class MyUser : IUser
{
        // Additional properties and functions not shown for brevity.
}

class MyUserStore : IUserRoleStore<MyUser>
{
    public bool IsInRole(string username, string role)
    {
       // Implementation not show for brevity.
    }


    /* We would then implement the rest of the required functions.

       We would have a data context here that has access to users,
       user-roles, and roles.
    */
}

Now we can pass MyUserStore to UserManager<TUser>, because MyUserStore is an IUserRoleStore<TUser>, which is an IUserStore<TUser>:

UserManager<MyUser> UM = new UserManager<MyUser>(new MyUserStore());

I suspect, then, that the source code for UserManager<TUser> uses reflection to find out whether the store passed into it at constructor implements one of IUserStore<TUserStore>'s "child interfaces", in order to be able to perform role checks (if it implements IUserRoleStore<TUser>) or password set/reset (if it implements IUserPasswordStore<TUser>).

I hope you find this useful because most documentation (MVC tutorials and such) don't tell us this detail. They tell us to use the UserStore<TUser> implementation of Microsoft.AspNet.Identity.EntityFramework - where all we have to do is pass in a custom User object (that implements IUser) and we're good to go.