AspNetCore.Identity 无法使用自定义 User/Role 实现
AspNetCore.Identity not working with custom User/Role implementation
因为我倾向于Guid
作为我的主键类型,所以我的User
和Role
类实现如下
public class User : IdentityUser<Guid, UserClaim, UserRole, UserLogin>
{
}
public class Role : IdentityRole<Guid, UserRole, RoleClaim>
{
}
注意UserClaim
、UserRole
、UserLogin
和RoleClaim
都是以同样的方式实现的
这是我的DbContext
实现
public class ApplicationDbContext : IdentityDbContext<User, Role, Guid, UserClaim, UserRole, UserLogin, RoleClaim, UserToken>
{
}
到目前为止一切都很好,除了 AspNetCore 的新 DI 容器默认情况下似乎不喜欢我的自定义实现。来自我的 Startup.cs 文件的以下代码行抛出如下所示的错误
services
.AddIdentity<User, Role>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
GenericArguments[0], 'NewCo.DomainModel.Models.Identity.User', on
'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`4[TUser,TRole,TContext,TKey]'
violates the constraint of type 'TUser'.
我假设这是因为默认的 Identity gremlin 被实现为使用 IdentityUser<string>
,而我使用的是 IdentityUser<Guid>
.
接下来我该做什么? (我完全没有想法)
注意:我正在构建微软的官方 .NET Core 和 ASP.NET Core 版本,截至周一(2016 年 6 月 27 日)和 Visual Studio 更新 3(如果那是对任何人有任何帮助)
由于您使用的是自定义键类型,因此您必须在调用时指定它 AddEntityFrameworkStores
:
services
.AddIdentity<User, Role>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders();
"UserStore`4[TUser,TRole,TContext,TKey]' violates the constraint of
type 'TUser'."
您需要使用 Guid 创建一个 UserStore,并更改您的 DbContext
public class ApplicationUser : IdentityUser<Guid> { }
public class ApplicationRole : IdentityRole<Guid> { }
public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, ApplicationDbContext, Guid>
{
public ApplicationUserStore(ApplicationDbContext context, IdentityErrorDescriber describer = null) : base(context, describer)
{
}
}
新的ApplicationDbContext继承
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
在你的startup.cs
services
.AddIdentity<ApplicationUser, ApplicationRole>()
.AddUserStore<ApplicationUserStore>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders();
我最终得到了这个解决方案:
实际上我做了自己的抽象 IdentityDbContext
然后你可以传递任何自定义模型,唯一的问题是在创建 db EF 时向除用户和角色(继承)以外的所有表添加一个 Disriminator 字段
public abstract class ApplicationDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : IdentityDbContext<TUser, TRole, TKey>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>
where TUserRole : IdentityUserRole<TKey>
where TUserLogin : IdentityUserLogin<TKey>
where TRoleClaim : IdentityRoleClaim<TKey>
where TUserToken : IdentityUserToken<TKey>
{
public ApplicationDbContext(DbContextOptions options) : base(options) { }
protected ApplicationDbContext() { }
public new DbSet<TRoleClaim> RoleClaims { get; set; }
public new DbSet<TRole> Roles { get; set; }
public new DbSet<TUserClaim> UserClaims { get; set; }
public new DbSet<TUserLogin> UserLogins { get; set; }
public new DbSet<TUserRole> UserRoles { get; set; }
public new DbSet<TUser> Users { get; set; }
public new DbSet<TUserToken> UserTokens { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
public class AppDbContext : ApplicationDbContext<ApplicationUser, ApplicationRole, Guid, ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin, ApplicationRoleClaim, ApplicationUserToken>
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
//public new DbSet<ApplicationUserClaim> UserClaims { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<AppDbContext, Guid>()
.AddDefaultTokenProviders()
.AddUserStore<UserStore<ApplicationUser, ApplicationRole, AppDbContext, Guid>>()
.AddRoleStore<RoleStore<ApplicationRole, AppDbContext, Guid>>()
public class ApplicationUser : IdentityUser<Guid>
{
public ApplicationUser()
{
//this.Id = Guid.NewGuid();
}
public ApplicationUser(string userName) : this() { this.UserName = userName; }
public Guid ClientId { get; set; }
//public new ICollection<ApplicationUserClaim> Claims { get; set; }
}
//public class ApplicationRole : IdentityRole<Guid, ApplicationUserRole, ApplicationRoleClaim>
public class ApplicationRole : IdentityRole<Guid>
{
public ApplicationRole()
{
//this.Id = Guid.NewGuid();
}
public ApplicationRole(string name) : this() { this.Name = name; }
}
public class ApplicationRoleClaim : IdentityRoleClaim<Guid> { }
//[NotMapped]
public class ApplicationUserClaim : IdentityUserClaim<Guid> { }
public class ApplicationUserLogin : IdentityUserLogin<Guid> { }
public class ApplicationUserRole : IdentityUserRole<Guid> { }
public class ApplicationUserToken : IdentityUserToken<Guid> { }
在使用自定义用户和角色的情况下将 Key 指定给 .AddEntityFrameworkStore() 方法entities.while 在启动时注册身份
.AddEntityFrameworkStores<IdentityDbContext, TKey>()
因为它默认使用字符串类型的键,如果是其他类型的键会导致错误。
因为我倾向于Guid
作为我的主键类型,所以我的User
和Role
类实现如下
public class User : IdentityUser<Guid, UserClaim, UserRole, UserLogin>
{
}
public class Role : IdentityRole<Guid, UserRole, RoleClaim>
{
}
注意UserClaim
、UserRole
、UserLogin
和RoleClaim
都是以同样的方式实现的
这是我的DbContext
实现
public class ApplicationDbContext : IdentityDbContext<User, Role, Guid, UserClaim, UserRole, UserLogin, RoleClaim, UserToken>
{
}
到目前为止一切都很好,除了 AspNetCore 的新 DI 容器默认情况下似乎不喜欢我的自定义实现。来自我的 Startup.cs 文件的以下代码行抛出如下所示的错误
services
.AddIdentity<User, Role>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
GenericArguments[0], 'NewCo.DomainModel.Models.Identity.User', on 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`4[TUser,TRole,TContext,TKey]' violates the constraint of type 'TUser'.
我假设这是因为默认的 Identity gremlin 被实现为使用 IdentityUser<string>
,而我使用的是 IdentityUser<Guid>
.
接下来我该做什么? (我完全没有想法)
注意:我正在构建微软的官方 .NET Core 和 ASP.NET Core 版本,截至周一(2016 年 6 月 27 日)和 Visual Studio 更新 3(如果那是对任何人有任何帮助)
由于您使用的是自定义键类型,因此您必须在调用时指定它 AddEntityFrameworkStores
:
services
.AddIdentity<User, Role>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders();
"UserStore`4[TUser,TRole,TContext,TKey]' violates the constraint of type 'TUser'."
您需要使用 Guid 创建一个 UserStore,并更改您的 DbContext
public class ApplicationUser : IdentityUser<Guid> { }
public class ApplicationRole : IdentityRole<Guid> { }
public class ApplicationUserStore : UserStore<ApplicationUser, ApplicationRole, ApplicationDbContext, Guid>
{
public ApplicationUserStore(ApplicationDbContext context, IdentityErrorDescriber describer = null) : base(context, describer)
{
}
}
新的ApplicationDbContext继承
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
在你的startup.cs
services
.AddIdentity<ApplicationUser, ApplicationRole>()
.AddUserStore<ApplicationUserStore>()
.AddEntityFrameworkStores<ApplicationDbContext, Guid>()
.AddDefaultTokenProviders();
我最终得到了这个解决方案:
实际上我做了自己的抽象 IdentityDbContext
然后你可以传递任何自定义模型,唯一的问题是在创建 db EF 时向除用户和角色(继承)以外的所有表添加一个 Disriminator 字段
public abstract class ApplicationDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : IdentityDbContext<TUser, TRole, TKey>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>
where TUserRole : IdentityUserRole<TKey>
where TUserLogin : IdentityUserLogin<TKey>
where TRoleClaim : IdentityRoleClaim<TKey>
where TUserToken : IdentityUserToken<TKey>
{
public ApplicationDbContext(DbContextOptions options) : base(options) { }
protected ApplicationDbContext() { }
public new DbSet<TRoleClaim> RoleClaims { get; set; }
public new DbSet<TRole> Roles { get; set; }
public new DbSet<TUserClaim> UserClaims { get; set; }
public new DbSet<TUserLogin> UserLogins { get; set; }
public new DbSet<TUserRole> UserRoles { get; set; }
public new DbSet<TUser> Users { get; set; }
public new DbSet<TUserToken> UserTokens { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
public class AppDbContext : ApplicationDbContext<ApplicationUser, ApplicationRole, Guid, ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin, ApplicationRoleClaim, ApplicationUserToken>
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
//public new DbSet<ApplicationUserClaim> UserClaims { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<AppDbContext, Guid>()
.AddDefaultTokenProviders()
.AddUserStore<UserStore<ApplicationUser, ApplicationRole, AppDbContext, Guid>>()
.AddRoleStore<RoleStore<ApplicationRole, AppDbContext, Guid>>()
public class ApplicationUser : IdentityUser<Guid>
{
public ApplicationUser()
{
//this.Id = Guid.NewGuid();
}
public ApplicationUser(string userName) : this() { this.UserName = userName; }
public Guid ClientId { get; set; }
//public new ICollection<ApplicationUserClaim> Claims { get; set; }
}
//public class ApplicationRole : IdentityRole<Guid, ApplicationUserRole, ApplicationRoleClaim>
public class ApplicationRole : IdentityRole<Guid>
{
public ApplicationRole()
{
//this.Id = Guid.NewGuid();
}
public ApplicationRole(string name) : this() { this.Name = name; }
}
public class ApplicationRoleClaim : IdentityRoleClaim<Guid> { }
//[NotMapped]
public class ApplicationUserClaim : IdentityUserClaim<Guid> { }
public class ApplicationUserLogin : IdentityUserLogin<Guid> { }
public class ApplicationUserRole : IdentityUserRole<Guid> { }
public class ApplicationUserToken : IdentityUserToken<Guid> { }
在使用自定义用户和角色的情况下将 Key 指定给 .AddEntityFrameworkStore() 方法entities.while 在启动时注册身份
.AddEntityFrameworkStores<IdentityDbContext, TKey>()
因为它默认使用字符串类型的键,如果是其他类型的键会导致错误。