Как расширить IdentityRole с помощью Web API 2 + AspNet Identity 2

Я пытаюсь расширить класс AspNet IdentityRole, представленный в шаблоне Web API 2 (с отдельными учетными записями) в последней версии Visual Studio 2013. Когда я нажимаю /api/roles, он возвращает пустой массив.

Модели идентичности

namespace API.Models
{
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more.
public class ApplicationUser : IdentityUser<string, IdentityUserLogin, ApplicationUserRole, IdentityUserClaim>, IUser, IUser<string>
{
    [NotMapped]
    public virtual UserProfile Profile { get; set; }

    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }

    //public virtual List<ApplicationUserRole> ApplicationRoles { get; set; }

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

public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
    public ApplicationRole() : base() { }

}

public class ApplicationUserRole : IdentityUserRole<string>
{
    public ApplicationUserRole()
        : base()
    { }

    public virtual ApplicationRole Role { get; set; }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser,ApplicationRole,string,IdentityUserLogin,ApplicationUserRole,IdentityUserClaim> 

{

     public ApplicationDbContext()
        : base("DefaultConnection")
    {
        base.Configuration.ProxyCreationEnabled = false;
    }

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

}

Конфигурация личности

namespace API
{
// Configure the application user manager used in this application. UserManager is defined in ASP.NET Identity and is used by the application.

public class ApplicationUserManager : UserManager<ApplicationUser, string>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> store)
        : base(store)
    {
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options,
        IOwinContext context)
    {
        var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));

        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };
        IDataProtectionProvider dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider =
                new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
        }
        return manager;
    }
}



public class ApplicationRoleManager : RoleManager<ApplicationRole, string>
{
    public ApplicationRoleManager(IRoleStore<ApplicationRole, string> store)
        : base(store)
    {
    }

    public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options,
        IOwinContext context)
    {
        var manager = new ApplicationRoleManager(new RoleStore<ApplicationRole>(context.Get<ApplicationDbContext>()));
        return manager;
    }

}

}


person Dushan Perera    schedule 04.09.2014    source источник
comment
Из любопытства, почему вы хотите расширить класс ролей? Я считаю, что в большинстве случаев вам действительно не нужно... вам нужно только добавить элементы в заявку. Большинство людей полагают, что для получения большей функциональности необходимо расширять, но это не всегда так.   -  person Erik Funkenbusch    schedule 05.09.2014
comment
Я хочу расширить роли, чтобы я мог добавить к ним объект Permissions, и я хочу расширить userRoles, чтобы я мог добавить объект виртуальной роли. Прямо сейчас, когда я включаю user.Roles при получении пользователя, он возвращает объекты UserRole, но я не могу, например, включить UserRole.Role, чтобы у меня были все мои данные.   -  person Dushan Perera    schedule 05.09.2014
comment
Зачем нужно добавлять объект Permissions в роли? Роли — это, по сути, просто тег. Если вы хотите создать сложную систему разрешений, я бы вместо этого создал объект сопоставления UserRole, который сопоставляет роли с разрешениями. Я понятия не имею, что вы подразумеваете под объектом виртуальной роли. Я думаю, вы идете об этом задом наперед.   -  person Erik Funkenbusch    schedule 05.09.2014
comment
Если бы у меня был объект сопоставления между ролями и разрешениями, я понимаю, что это были бы отношения «многие ко многим», но я хочу только один к одному, поэтому я хотел добавить объект разрешений как свойство роли .   -  person Dushan Perera    schedule 05.09.2014
comment
Под объектом виртуальной роли я подразумеваю вот что. Допустим, я получаю пользователя, используя db.User.Where(t=›t.Id == id). Если я хочу включить роли в объект, я добавляю .Include(Roles) перед предложением where. Это заполняет свойство Roles[] в IdentityUser подключенными IdentityUserRoles. Однако, если мне нужно имя роли, я не могу сделать еще один шаг и сказать, например, .Include(Roles.Role), потому что у IdentityUserRoles нет свойства навигации для роли, представленной свойством RoleId.   -  person Dushan Perera    schedule 05.09.2014
comment
Кажется, вы путаете RoleManager (и UserManager) с выполнением запросов к вашей базе данных. Это две разные вещи. Если вам нужна роль для пользователя, используйте RoleManager.   -  person Erik Funkenbusch    schedule 05.09.2014
comment
Я понимаю это, но я хочу, чтобы все это было в одном вложенном объекте, который я мог бы передать обратно в свое клиентское приложение. Даже если я использовал RoleManager, свойство Roles в IdentityUser имеет тип IdentityUserRole. Как бы вы подошли к этому по-другому?   -  person Dushan Perera    schedule 05.09.2014


Ответы (1)


твоя ошибка здесь

ApplicationDbContext : IdentityDbContext<ApplicationUser>

ваш контекст БД - это степень от IdentityDbContext<ApplicationUser>, которая является базой от

IdentityDbContext<TUser, IdentityRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>

ApplicationDbContext будет генерировать IdentityRole, когда вы действительно хотите ApplicationRole в качестве своей роли.

Измените свой ApplicationDbContext на

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserLogin, ApplicationUserRole, IdentityUserClaim>
{

 public ApplicationDbContext()
    : base("DefaultConnection", false)
 {
    base.Configuration.ProxyCreationEnabled = false;
 }

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

вам не нужно переопределять OnModelCreating и добавлять роли свойств в этой точке.

поскольку у вас есть свойство навигации в ApplicationUserRole, вы должны добавить отображение конфигурации

protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    modelBuilder.Entity<ApplicationUserRole>().HasRequired(ur => ur.Role).WithMany().HasForeignKey(ur => ur.RoleId);
}

IdentityModel.cs должен быть таким:

public class ApplicationUserRole : IdentityUserRole<string>
{
    public ApplicationUserRole()
        : base()
    { }

    public virtual ApplicationRole Role { get; set; }
}

public class ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
    public ApplicationRole() : base() { }

    public ApplicationRole(string name, string description)
        : base()
    {
        this.Name = name;
        this.Description = description;
    }

    public string Description { get; set; }
}

public class ApplicationUser : IdentityUser<string, IdentityUserLogin, ApplicationUserRole, IdentityUserClaim>
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserLogin, ApplicationUserRole, IdentityUserClaim>
{

    public ApplicationDbContext()
        : base("DefaultConnection")
    {
        base.Configuration.ProxyCreationEnabled = false;
    }

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
    protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<ApplicationUserRole>().HasRequired(ur => ur.Role).WithMany().HasForeignKey(ur => ur.RoleId);
    }
}

identityconfig.cs должен быть таким:

public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, string, IdentityUserLogin, ApplicationUserRole, IdentityUserClaim>, IUserStore<ApplicationUser>
{
    public ApplicationUserStore(ApplicationDbContext context)
        : base(context)
    {
    }   
}

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager(IUserStore<ApplicationUser> store)
        : base(store)
    {
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) 
    {
        var manager = new ApplicationUserManager(new ApplicationUserStore(context.Get<ApplicationDbContext>()));
        ....
    }
}
public class ApplicationRoleStore : RoleStore<ApplicationRole, string, ApplicationUserRole>
{
    public ApplicationRoleStore(ApplicationDbContext context)
        : base(context)
    {

    }
}
public class ApplicationRoleManager : RoleManager<ApplicationRole, string>
{
    public ApplicationRoleManager(IRoleStore<ApplicationRole, string> store)
        : base(store)
    {
    }

    public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options,
        IOwinContext context)
    {
        var manager = new ApplicationRoleManager(new ApplicationRoleStore(context.Get<ApplicationDbContext>()));
        return manager;
    }
}
person Aiska Hendra    schedule 04.09.2014
comment
Когда я пытаюсь сделать это, я получаю следующие ошибки (как для пользователя, так и для роли): Тип «API.Models.ApplicationRole» не может использоваться в качестве параметра типа «TRole» в универсальном типе или методе... Нет неявного преобразование ссылки из «API.Models.ApplicationRole» в «Microsoft.AspNet.Identity.EntityFramework.IdentityRole‹string,API.Models.ApplicationUserRole›». - person Dushan Perera; 04.09.2014
comment
Ах, извините, я забыл, вам нужно изменить ApplicationRole: IdentityRole‹string, Applic‌​ationUserRole› - person Aiska Hendra; 05.09.2014
comment
Это исправило мою страницу моделей, но теперь мой RoleManager и UserManager взрываются с аналогичной ошибкой (не удается преобразовать ApplicationRole в IdentityRole): var manager = new ApplicationRoleManager(new RoleStore‹ApplicationRole›(context.Get‹ApplicationDbContext›())) ; - person Dushan Perera; 05.09.2014
comment
Хм, обновление 3 и 4, похоже, не исправили ошибку. Я обновлю свой пост, чтобы показать свой код в том виде, в котором он есть сейчас. -- Опубликовано - person Dushan Perera; 05.09.2014
comment
new RoleStore‹ApplicationRole›(context.Get‹ApplicationDbContext›()) ‹ — здесь возникает ошибка при создании нового RoleStore. Нет неявного преобразования ссылок из API.Models.ApplicationRole в IdentityRole. - person Dushan Perera; 05.09.2014
comment
Отлично работает, за исключением случаев, когда вы пытаетесь установить собственный валидатор в методе ApplicationUserManager Create(). эта строка manager.UserValidator = new CustomUserValidator<ApplicationUser>(manager); не компилируется. добавив наследование IUser к ApplicationUser, разберитесь. public class ApplicationUser : IdentityUser<string, IdentityUserLogin, ApplicationUserRole, IdentityUserClaim>, IUser - person Issac; 28.06.2015