每个租户的唯一用户名和电子邮件

Unique UserName & Email per tenant

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

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

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

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

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

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

大多数结果只会涵盖 Entity Framework 个方面,就好像 overriding OnModelCreating(...) method. 的问题与 ASP.NET 身份的非核心版本有关。

我想知道我是否应该继续研究 OnModelCreating 方法?

或者,也许 Identity 周围还需要覆盖其他内容?

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

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

然后,假设您要使用 ASP.NET Core with Identity 模板注册用户,您可以这样做:

[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<ApplicationUser>

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 时,将在创建用户之前进行验证。