gpt4 book ai didi

c# - Multi-Tenancy 应用程序中的IdentityRole

转载 作者:太空宇宙 更新时间:2023-11-03 23:08:26 25 4
gpt4 key购买 nike

我正在构建一个ASP.NET MVC 5多租户解决方案,并且在角色方面有一个小问题。我创建了一个自定义角色实体,如下所示:

public class ApplicationRole : IdentityRole, ITenantEntity
{
public ApplicationRole()
: base()
{
}

public ApplicationRole(string roleName)
: base(roleName)
{
}

public int? TenantId { get; set; }
}


并完成了所有其他需要的工作..除了一件事之外,一切都运转良好。当租户管理员尝试添加新角色时,如果另一个租户创建的角色已经使用了该角色的名称,则他将得到以下错误:

名称管理员已被使用。

显然,存在一些潜在的检查,以检查角色名称在ASP.NET Identity中某个地方是否唯一。有什么方法可以更改此设置,以便我可以通过“ TenantId +名称”而不是仅名称来查找唯一性吗?

更新

使用dotPeek反编译DLL,我发现我需要创建自己的IIdentityValidator实现,并且当然要修改RoleManager。所以,这是我的角色验证器:

public class TenantRoleValidator : IIdentityValidator<ApplicationRole>
{
private RoleManager<ApplicationRole, string> Manager { get; set; }

/// <summary>Constructor</summary>
/// <param name="manager"></param>
public TenantRoleValidator(RoleManager<ApplicationRole, string> manager)
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}

this.Manager = manager;
}

/// <summary>Validates a role before saving</summary>
/// <param name="item"></param>
/// <returns></returns>
public virtual async Task<IdentityResult> ValidateAsync(ApplicationRole item)
{
if ((object)item == null)
{
throw new ArgumentNullException("item");
}

var errors = new List<string>();
await this.ValidateRoleName(item, errors);
return errors.Count <= 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
}

private async Task ValidateRoleName(ApplicationRole role, List<string> errors)
{
if (string.IsNullOrWhiteSpace(role.Name))
{
errors.Add("Name cannot be null or empty.");
}
else
{
var existingRole = await this.Manager.Roles.FirstOrDefaultAsync(x => x.TenantId == role.TenantId && x.Name == role.Name);
if (existingRole == null)
{
return;
}

errors.Add(string.Format("{0} is already taken.", role.Name));
}
}
}


我的角色经理:

public class ApplicationRoleManager : RoleManager<ApplicationRole>
{
public ApplicationRoleManager(IRoleStore<ApplicationRole, string> store)
: base(store)
{
this.RoleValidator = new TenantRoleValidator(this);
}

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


但是,我现在收到一个新错误:

无法在具有唯一索引“ RoleNameIndex”的对象“ dbo.AspNetRoles”中插入重复的键行。重复的键值为(管理员)。
该语句已终止

我可以修改数据库以更改假定的索引,但是我需要在安装时使其正确,因为我正在构建的解决方案是CMS,将来将用于许多安装...

我的第一个想法是我需要以某种方式修改 EntityTypeConfiguration<T>实体的 ApplicationRole。但是我当然不能立即访问它...它只是由 ApplicationDbContext自动创建的,因为它继承自 IdentityDbContext<ApplicationUser>。我将不得不更深入地研究反汇编的代码,看看我能找到什么...

更新2

好的,我正在使用 base.OnModelCreating(modelBuilder);获取身份成员资格表的配置。我删除了该行,并将反编译的代码复制到了我的 OnModelCreating方法中,但是删除了用于创建索引的部分。这(并删除数据库中的索引)解决了我以前遇到的错误..但是,我又遇到了1个错误,现在我完全感到困惑了...

我收到如下错误消息:

无法将值NULL插入表“ dbo.AspNetRoles”的“名称”列中;列不允许为空。 INSERT失败。
该语句已终止。

这没有任何意义,因为在调试时,我可以清楚地看到我在尝试创建的角色中传递了Name和TenantId。这是我的代码:

var result = await roleManager.CreateAsync(new ApplicationRole
{
TenantId = tenantId,
Name = role.Name
});


这些值不为null,所以我不知道这里发生了什么。非常感激任何的帮助。

更新3

我创建了自己的RoleStore,该继承自 RoleStore<ApplicationRole>,并且覆盖了 CreateAsync((ApplicationRole role)方法,因此我可以调试此部分并查看发生了什么。见下文:

enter image description here

继续运行代码后,我仍然在死亡的黄屏上看到以下错误:

enter image description here

任何人,任何人,请帮助您阐明此处发生的情况以及是否有可能解决此问题。

更新4

好的,我现在更接近答案了。我从头开始创建了一个新的数据库(允许EF创建它),我注意到并没有创建Name列……只有Id和TenantId ..这意味着前一个错误是因为我现有的数据库已经具有“名称”列,并且已设置为“非空..”,并且由于某种原因,EF忽略了我的角色实体的“名称”列,我认为这与继承自IdentityRole的原因有关。

这是我的模型配置:

var rolesTable = modelBuilder.Entity<ApplicationRole>().ToTable("AspNetRoles");

rolesTable.Property(x => x.TenantId)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true, Order = 1 }));

rolesTable.Property(x => x.Name)
.IsRequired()
.HasMaxLength(256)
.HasColumnAnnotation("Index", new IndexAnnotation(new IndexAttribute("RoleNameIndex") { IsUnique = true, Order = 2 }));

rolesTable.HasMany(x => x.Users).WithRequired().HasForeignKey(x => x.RoleId);


我认为这可能与索引配置有关,因此我只删除了这两个(TenantId和Name),并用以下内容替换了它:

rolesTable.Property(x => x.Name)
.IsRequired()
.HasMaxLength(256);


但是,“名称”列仍未创建。现在和以前之间的唯一区别是,我使用的是 modelBuilder.Entity<ApplicationRole>(),而我想默认的是 modelBuilder.Entity<IdentityRole>()

如何让EF识别基类 IdentityRole的Name属性和派生类 ApplicationRole的TenantId属性?

最佳答案

好,我已经解决了。答案是首先遵循我在原始帖子中添加的所有更新,然后最后要做的是使我的ApplicationDbContextIdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserLogin, IdentityUserRole, IdentityUserClaim>继承而不仅仅是IdentityDbContext<ApplicationUser>

关于c# - Multi-Tenancy 应用程序中的IdentityRole,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40336574/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com