【问题标题】:Unique UserName & Email per tenant每个租户的唯一用户名和电子邮件
【发布时间】:2019-01-08 10:44:13
【问题描述】:

我正在使用 ASP.NET Core 2.1 编写一个多租户应用程序。

我想覆盖默认的用户创建相关的验证机制。

目前我无法使用相同的UserName 创建多个用户。

我的ApplicationUser 模型有一个名为TenantID 的字段。

我想要实现的目标:UserName & EmailAddress 对于每个租户来说必须是唯一的。

我一直在谷歌上搜索一个解决方案,但在这个解决方案上没有找到很多关于 asp.net core 的信息。

大部分结果只会涵盖Entity Framework 方面,好像只是overriding OnModelCreating(...) 方法的问题。 Some 与 ASP.NET Identity 的非核心版本相关。

我想知道我是否应该继续调查OnModelCreating 方法?

或者,Identity 周围还有其他需要覆盖的东西?

【问题讨论】:

标签: c# asp.net-core multi-tenant asp.net-core-identity


【解决方案1】:

首先,您需要禁用 Identity 的内置验证机制:

services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
    // disable the built-in validation
    options.User.RequireUniqueEmail = false;
})
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

然后,假设您正在使用带有标识模板的 ASP.NET Core 注册用户,您可以这样做:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;

    if (ModelState.IsValid)
    {
        return View(model); 
    }

    // check for duplicates
    bool combinationExists = await _context.Users
        .AnyAsync(x => x.UserName == model.UserName 
                 && x.Email == model.Email
                 && x.TenantId == model.TenantId);

    if (combinationExists)
    {
        return View(model);
    }

    // create the user otherwise
}

如果您不想在控制器中进行这种检查并希望保留身份流,则可以非常简单地创建自己的 IUserValidator&lt;ApplicationUser&gt;

public class MultiTenantValidator : IUserValidator<ApplicationUser>
{
    public async Task<IdentityResult> ValidateAsync(UserManager<ApplicationUser> manager, ApplicationUser user)
    {
        bool combinationExists = await manager.Users
            .AnyAsync(x => x.UserName == user.UserName 
                        && x.Email == user.Email
                        && x.TenantId == user.TenantId);

        if (combinationExists)
        {
            return IdentityResult.Failed(new IdentityResult { Description = "The specified username and email are already registered in the given tentant" });
        }

        // here the default validator validates the username for valid characters,
        // let's just say all is good for now
        return IdentityResult.Success;
    }
}

然后你会告诉 Identity 使用你的验证器:

services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddUserValidator<MultiTenantValidator>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

这样,当您调用UserManager.CreateAsync 时,将在创建用户之前进行验证。

【讨论】:

  • 非常感谢您的回答!很快就会调查。
  • @AlexHerman 欢迎您。我添加了第二个答案以防万一:)
  • 我尝试了第二个答案,但是在为另一个租户注册同一电子邮件时,它给了我错误“唯一索引'UserNameIndex'”,我怎样才能使用户名不唯一?另外,你忘了在“manager.Users.AnyAsync”之前写等待
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-09
  • 1970-01-01
  • 2019-04-26
  • 2021-10-04
  • 1970-01-01
  • 2022-01-26
相关资源
最近更新 更多