AspNetCore.Identity 与自定义用户/角色实现不兼容。

4

因为我倾向于使用Guid作为我的主键类型,所以我的UserRole类实现如下:

public class User : IdentityUser<Guid, UserClaim, UserRole, UserLogin>
{
}

public class Role : IdentityRole<Guid, UserRole, RoleClaim>
{
}

请注意,UserClaimUserRoleUserLoginRoleClaim都是以相同的方式实现的。
这是我的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', 在 'Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore`4[TUser,TRole,TContext,TKey]' 上违反了类型'TUser'的约束。

我猜这是因为默认的 Identity gremlin 实现使用 IdentityUser<string>,而我正在使用 IdentityUser<Guid>

接下来该怎么办?(我已经没有任何主意了)

注意:我正在构建针对 Microsoft 官方 .NET Core 和 ASP.NET Core 发布版本以及 Visual Studio Update 3(如果对任何人有帮助)


你为什么要实现自己的 UserClaimUserRoleUserLoginRoleClaimUserToken 版本呢?我在我的应用程序中使用 Guid 作为键,没有遇到 DI 的问题。我实现了我的用户和角色模型,例如 AppUser : IdentityUser<Guid>AppRole : IdentityRole<Guid>。我还没有发现需要自定义其他身份模型的必要性。 - Brad
@Brad,我猜为了保持一致性——尽管如果你的方法可行,那可能是一个(愉快的)妥协。 - Matthew Layton
这里报告了一个错误:https://github.com/aspnet/Identity/issues/829#issuecomment-238804731 - VahidN
4个回答

6

因为您正在使用自定义密钥类型,所以在调用AddEntityFrameworkStores时必须指定它:

services
    .AddIdentity<User, Role>()
    .AddEntityFrameworkStores<ApplicationDbContext, Guid>()
    .AddDefaultTokenProviders();

根据文档完全没问题,但我尝试了那个方法,仍然得到相同的错误。 :-( - Matthew Layton
你应该分享所有的实体。很可能有一个实体导致了通用参数不兼容。 - Kévin Chalet
你能否将其放入上下文中(例如使用代码示例)?我不完全明白你的意思。 - Matthew Layton
我只是指的是你的UserClaim、UserRole、UserLogin、RoleClaim和UserToken实体 ;) - Kévin Chalet
如果您正在使用EF进行存储,那么一切都很好。但是如果使用自定义存储呢? - M Kenyon II
3
我没有 .AddEntityFrameworkStores<ApplicationDbContext, Guid>(),只有.AddEntityFrameworkStores<ApplicationDbContext>() - Dmitrij Polyanin

5
我最终采用了这个解决方案:
实际上,我创建了自己的抽象IdentityDbContext,然后可以传递任何自定义模型。唯一的问题是在创建数据库时,EF会向除用户和角色(继承)之外的所有表添加一个Discriminator字段。
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> { }

0

如果在启动时注册身份验证,使用自定义用户和角色实体,则需要在.AddEntityFrameworkStore()方法中指定密钥。

.AddEntityFrameworkStores<IdentityDbContext, TKey>()

因为它默认使用字符串键类型,如果使用其他键类型会导致错误。


1
这对于完全定制的身份实现中的自定义键类型无效。请参见此处的已接受答案:https://dev59.com/eaPia4cB1Zd3GeqPzHgZ - Matthew Layton

0
"UserStore`4[TUser,TRole,TContext,TKey]" 违反了类型约束 '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();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接