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

时间:2018-07-31 23:41:35

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

我正在使用ASP.NET Core 2.1对多租户应用进行编码。

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

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

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

我要实现的目标:UserNameEmailAddress每个租户必须唯一。

我一直在寻找一种解决方案,但是没有找到关于asp.net core的更多信息。

大多数结果仅涉及Entity Framework个方面,就好像这只是overriding OnModelCreating(...)方法的问题一样。 Some与ASP.NET Identity的非核心版本有关。

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

也许,Identity周围还有其他需要重写的东西吗?

1 个答案:

答案 0 :(得分:4)

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

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

public class MultiTenantValidator : IUserValidator<ApplicationUser>
{
    public async Task<IdentityResult> ValidateAsync(UserManager<ApplicationUser> manager, ApplicationUser user)
    {
        bool combinationExists = 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时,验证将在创建用户之前进行。