Adding users to roles in ASP.Net Identity with EF 6 causes new roles and users to be created

huangapple go评论54阅读模式
英文:

Adding users to roles in ASP.Net Identity with EF 6 causes new roles and users to be created

问题

我遇到了问题,希望有人能提供答案。我创建了一个带有 Identity 的 Blazor 应用程序,以下是我的 dbContext 看起来是这样的:

public class ApplicationDbContext : IdentityDbContext<AppUser, AppRole, string, 
    AppUserClaim, AppUserRole, AppUserLogin, AppRoleClaim, AppUserToken>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
       
        builder.Entity<AppUser>().ToTable("Users");
     
        builder.Entity<AppUser>().Property(x => x.FirstName).IsRequired();
        builder.Entity<AppUser>().Property(x => x.LastName).IsRequired();
        builder.Entity<AppUser>().Property(x => x.LastLoginDate);
        builder.Entity<AppUser>().HasMany(x => x.Roles).WithOne(x => x.User).HasForeignKey(x => x.UserId).IsRequired();

        builder.Entity<AppUserRole>().ToTable("UserRoles").HasOne(c => c.Role).WithMany(c => c.UserRoles).HasForeignKey(c => c.UserId);

        builder.Entity<AppRole>().ToTable("Roles");
        builder.Entity<AppRole>().Property(x => x.Description);
        builder.Entity<AppRole>().HasMany(x => x.UserRoles).WithOne(e => e.Role).HasForeignKey(ur => ur.RoleId).IsRequired();
        builder.Entity<AppRole>().HasMany(x => x.RoleClaims).WithOne(e => e.Role).HasForeignKey(x => x.RoleId).IsRequired();
        
        builder.Entity<AppRoleClaim>().ToTable("RoleClaims");
        builder.Entity<AppRoleClaim>().HasOne(x => x.Role);

        builder.Entity<AppUserClaim>().ToTable("UserClaims");            
    }
}

在我的 program.cs 中,我有以下代码:

builder.Services.AddIdentity<AppUser, AppRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddTransient<RoleManager<AppRole>>();

以下是我的 Identity 类:

public class AppRole : IdentityRole
{ 
    public string? Description { get; set; }
    public virtual ICollection<AppUserRole>? UserRoles { get; set; }
    public virtual ICollection<AppRoleClaim>? RoleClaims { get; set; }

    public AppRole()
    {
    }
}

public class AppRoleClaim : IdentityRoleClaim<string>
{
    public virtual AppRole Role { get; set; }

    public AppRoleClaim()
    {
        Role = new AppRole();
    }
}

public class AppUser : IdentityUser
{
    public string FirstName { get; set; } 
    public string LastName { get; set; }
    public DateTimeOffset? LastLoginDate { get; set; }
    public byte[]? Photo { get; set; }
    public virtual ICollection<AppUserRole> Roles { get; set; }

    public AppUser()
    {
        FirstName = "";
        LastName = "";
        Roles = new List<AppUserRole>(); 
    }
}

public class AppUserClaim : IdentityUserClaim<string>
{
}

public class AppUserLogin : IdentityUserLogin<string>
{
}

public class AppUserRole : IdentityUserRole<string>
{
    public virtual AppUser User { get; set; }
    public virtual AppRole Role { get; set; }

    public AppUserRole()
    {
        User = new AppUser();
        Role = new AppRole();
    }
}

public class AppUserToken : IdentityUserToken<string>
{
}

这是我的表结构:

Adding users to roles in ASP.Net Identity with EF 6 causes new roles and users to be created

最后,我的问题是,当我调用 UserManager.CreateAsync(NewUser) 时,用户会正确创建,但是当我尝试将新创建的用户添加到一个角色中,例如管理员角色,如下所示 await UserManager.AddToRoleAsync(NewUser, "Admin"); 它不会抛出任何错误,但发生的情况是它创建一个新的用户,用户名、姓氏等都为 null,然后将一个具有 null 名称和 null 标准化名称的新角色添加到角色表中。然后将该角色添加到 UserRoles 表中,所有这些操作都没有出现任何错误。

根据微软的文档,这应该创建一个新用户并将该用户添加到 Admin 角色中。我是根据以下文档构建的:https://learn.microsoft.com/en-us/aspnet/core/security/?view=aspnetcore-6.0

英文:

I have hit a wall on this and hope someone else has the answer, I created a Blazor app with Identity this is what my dbContext looks like:

public class ApplicationDbContext : IdentityDbContext&lt;AppUser, AppRole, string, 
    AppUserClaim,AppUserRole,AppUserLogin,AppRoleClaim,AppUserToken&gt;
{
    public ApplicationDbContext(DbContextOptions&lt;ApplicationDbContext&gt; options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
       
        builder.Entity&lt;AppUser&gt;().ToTable(&quot;Users&quot;);
     
        builder.Entity&lt;AppUser&gt;().Property(x =&gt; x.FirstName).IsRequired();
        builder.Entity&lt;AppUser&gt;().Property(x =&gt; x.LastName).IsRequired();
        builder.Entity&lt;AppUser&gt;().Property(x =&gt; x.LastLoginDate);
        builder.Entity&lt;AppUser&gt;().HasMany(x =&gt; x.Roles).WithOne(x=&gt;x.User).HasForeignKey(x=&gt;x.UserId).IsRequired();

        builder.Entity&lt;AppUserRole&gt;().ToTable(&quot;UserRoles&quot;).HasOne(c =&gt; c.Role).WithMany(c =&gt; c.UserRoles).HasForeignKey(c =&gt; c.UserId);

        builder.Entity&lt;AppRole&gt;().ToTable(&quot;Roles&quot;);
        builder.Entity&lt;AppRole&gt;().Property(x =&gt; x.Description);
        builder.Entity&lt;AppRole&gt;().HasMany(x =&gt; x.UserRoles).WithOne(e =&gt; e.Role).HasForeignKey(ur =&gt; ur.RoleId).IsRequired();
        builder.Entity&lt;AppRole&gt;().HasMany(x =&gt; x.RoleClaims).WithOne(e=&gt;e.Role).HasForeignKey(x=&gt;x.RoleId).IsRequired();
        
        builder.Entity&lt;AppRoleClaim&gt;().ToTable(&quot;RoleClaims&quot;);
        builder.Entity&lt;AppRoleClaim&gt;().HasOne(x =&gt; x.Role);

        builder.Entity&lt;AppUserClaim&gt;().ToTable(&quot;UserClaims&quot;);            
    }
}

And in my program.cs, I have this code:

builder.Services.AddIdentity&lt;AppUser, AppRole&gt;()
            .AddEntityFrameworkStores&lt;ApplicationDbContext&gt;();
builder.Services.AddTransient&lt;RoleManager&lt;AppRole&gt;&gt;();

Here are my Identity classes:

public class AppRole:IdentityRole
{ 
    public string? Description { get; set; }
    public virtual ICollection&lt;AppUserRole&gt;? UserRoles { get; set; }
    public virtual ICollection&lt;AppRoleClaim&gt;? RoleClaims { get; set; }

    public AppRole()
    {
    }
}

public class AppRoleClaim : IdentityRoleClaim&lt;string&gt;
{
    public virtual AppRole Role { get; set; }

    public AppRoleClaim()
    {
        Role = new AppRole();
    }
}

public class AppUser : IdentityUser
{
    public string FirstName { get; set; } 
    public string LastName { get; set; }
    public DateTimeOffset? LastLoginDate { get; set; }
    public byte[]? Photo { get; set; }
    public virtual ICollection&lt;AppUserRole&gt; Roles { get; set; }

    public AppUser()
    {
        FirstName = &quot;&quot;;
        LastName = &quot;&quot;;
        Roles = new List&lt;AppUserRole&gt;(); 
    }
}

public class AppUserClaim : IdentityUserClaim&lt;string&gt;
{
}

public class AppUserLogin : IdentityUserLogin&lt;string&gt;
{
}

public class AppUserRole : IdentityUserRole&lt;string&gt;
{
    public virtual AppUser User { get; set; }
    public virtual AppRole Role { get; set; }

    public AppUserRole()
    {
        User = new AppUser();
        Role = new AppRole();
    }
}

public class AppUserToken : IdentityUserToken&lt;string&gt;
{
}

And this is my table structure:

Adding users to roles in ASP.Net Identity with EF 6 causes new roles and users to be created

And finally my question , when I call UserManager.CreateAsync(NewUser) a user is correctly created, however when I try to add the newly created user to a role for example the admin role like so await UserManager.AddToRoleAsync(NewUser, &quot;Admin&quot;); it does not throw any error, but what happens is it creates a new user with null user name, first name etc and it adds a new role to the roles table with a null Name and null normalized name. Then it adds that role to the UserRoles table. All without any errors.

According to MS Documentation this should create one new user and add that user to the Admin role. Docs I built this from are here https://learn.microsoft.com/en-us/aspnet/core/security/?view=aspnetcore-6.0

答案1

得分: 0

在今天的一些调查后,我弄清楚了发生了什么事情。看一下我的 AppUserRole

public class AppUserRole : IdentityUserRole<string>
{
    public virtual AppUser User { get; set; }
    public virtual AppRole Role { get; set; }
    public AppUserRole()
    {
        User = new AppUser();
        Role = new AppRole();
    }
}

由于我新建了一个新的 AppUser() 和一个新的 AppRole(),它们依次调用了基类构造函数,其中 IdentityRole 将其 Id 属性设置为一个新的 Guid,当调用 IdentityUser 的构造函数时,同样会发生这种情况。我通过查看 AspNetCore.Identity 源代码找到了这一点。因此,EntityFramework 正确执行了其工作,它看到一个全新的 AppUserRole,带有新的 IdentityUser 和新的 IdentityRole,由于这些是指向 AppRole 的导航属性,它在数据库中创建了它们。

简而言之,修复方法是使 AppUserRole 类中的导航属性可为空,并不在构造函数中创建它们,如下所示:

public class AppUserRole : IdentityUserRole<string>
{
    public virtual AppUser? User { get; set; }
    public virtual AppRole? Role { get; set; }
    public AppUserRole()
    {
        
    }
}
英文:

After doing some digging today I figured out what was going on. Have a look at my AppUserRole class

public class AppUserRole : IdentityUserRole&lt;string&gt;
{
    public virtual AppUser User { get; set; }
    public virtual AppRole Role { get; set; }
    public AppUserRole()
    {
        User = new AppUser();
        Role = new AppRole();
    }
}

Since I was newing up a new AppUser() and a new AppRole() they in turn were calling the base class constructors in which IdentityRole sets its Id property to a new Guid the same thing happens when the constructor of IdentityUser is called. I found that out by looking at the AspNetCore.Identity source code. So EntityFramework was correctly doing its job, it saw a brand new AppUserRole with a new IdentityUser and new IdentityRole and since these were navigation properties to AppRole it created them in the database.

TLDR The fix was to make the navigation properties in the AppUserRole class nullable and not new them up in the constructor as in below:

public class AppUserRole : IdentityUserRole&lt;string&gt;
{
    public virtual AppUser? User { get; set; }
    public virtual AppRole? Role { get; set; }
    public AppUserRole()
    {
        
    }
}

huangapple
  • 本文由 发表于 2023年2月27日 11:48:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75576618.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定