Authorize and GetRoles doesn't work in ASP.NET

2020-07-25 08:18发布

问题:

I am using ASP.NET Identity 2.1.0 using Entity Framework implementation.
Authentication works fine but role based security has problem. Although I've added role to the user but this code returns empty :

  var roles= UserManager.GetRoles(User.Identity.GetUserId());

Also Authorization based on roles of logged in user fails. when user redirects to a controller like below application redirects him to the login page.

  [Authorize(Roles = "Admin")]
    public abstract partial class AdminAreaController : Controller
    {

In order to add ASP.NET Identity, first, I have created custom user class to add profile data :

    public class BasemapUser : IdentityUser
{
    [MaxLength(100)]
    public string Name { get; set; }

    [MaxLength(100)]
    public string CompanyName { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<BasemapUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        ClaimsIdentity userIdentity =
            await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }
}

This is DbContext class :

    public class WebCoreMapDbContext : IdentityDbContext<BasemapUser>
{
    public WebDbContext()
        : base("WebDbContext")
    {
    }

    public static WebCoreMapDbContext Create()
    {
        return new WebCoreMapDbContext();
    }


    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
       modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
       modelBuilder.Entity<IdentityUserRole>().HasKey(r => new {r.RoleId, r.UserId});
    }
}

I created database using EF Migration commands in power shell. I see two extra columns in IdentityUserRoles table which I haven't seen in other samples of ASP.NET identity

I used this code to add default admin user and role:

        public static void Start()
    {
        var userManager = HttpContext.Current.GetOwinContext().GetUserManager<BasemapUserManager>();
        var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
        const string name = "someEmail@gmail.com";
        const string password = "somePassword";
        const string roleName = "Admin";

        //Create Role Admin if it does not exist
        IdentityRole role = roleManager.FindByName(roleName);
        if (role == null)
        {
            role = new IdentityRole(roleName);
            IdentityResult roleresult = roleManager.Create(role);
        }

        BasemapUser user = userManager.FindByName(name);
        if (user == null)
        {
            user = new BasemapUser {UserName = name, Email = name};
            IdentityResult result = userManager.Create(user, password);
            result = userManager.SetLockoutEnabled(user.Id, false);
        }

        // Add user admin to Role Admin if not already added
        IList<string> rolesForUser = userManager.GetRoles(user.Id);
        if (!rolesForUser.Contains(role.Name))
        {
            IdentityResult result = userManager.AddToRole(user.Id, role.Name);

        }
    }

Admin user and role have been stored in database successfully but stored record in IdentityUserRoles table contains null value :

Why GetRoles returns nothing for the user who has that role in database? also other APIs like IsInRole doesn't work as expected. Is it because foreign keys which added to IdentityUserRoles table?

回答1:

The problem was unnecessary columns which have added to Identity tables.

Since DbContext extends from IdentityDbContext, I have to call base.OnModelCreating since the IdentityDbContext defines it for mapping Identity classes. I haven't called that in the my code which caused the issues

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
       modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);
       modelBuilder.Entity<IdentityUserRole>().HasKey(r => new {r.RoleId, r.UserId});
    }

Has to change to

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
       base.OnModelCreating(modelBuilder);

      // modelBuilder.Entity<IdentityUserLogin>().HasKey<string>(l => l.UserId);                // do not add this
      // modelBuilder.Entity<IdentityUserRole>().HasKey(r => new {r.RoleId, r.UserId});         // do not add this
      // other mapping codes
    }