如何在多租户环境中使用 Asp.Net 核心标识



我有一个具有默认身份处理的 Asp.Net Core应用程序。现在我想将其用于多域。我用DomainId扩展了ApplicationUser。我如何不仅处理用户名/电子邮件来验证/注册用户,还处理当前的域ID?

当用户注册、登录系统时获取当前 DomainId 不是问题,我有一个有效的多租户 Asp.Net 核心系统。我只在使用域ID进行用户管理方面遇到问题。

这有什么设置吗?我应该覆盖什么才能获得此功能?例如UserStore,UserManager?

我找到了一些旧 Asp.Net 标识的教程,例如:https://www.scottbrady91.com/ASPNET-Identity/Quick-and-Easy-ASPNET-Identity-Multitenancy但是我找不到任何关于新 Asp.Net 核心身份的教程。

终于我想通了。因此,首先,我必须将用户电子邮件设置为不唯一。旁注:我也使用电子邮件作为用户名,我不喜欢问用户的用户名:

services.Configure<IdentityOptions>(options =>
{
    options.User.RequireUniqueEmail = false;
});

当新用户自己注册时,我将当前的域ID合并到用户名,这有助于用户使用相同的电子邮件/用户名通过完全不同的域注册到系统中。

然后我必须创建自定义用户管理器,在其中覆盖FindByEmail:

using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MultiShop.Core.Repositories.User;
using MultiShop.Core.Tenant;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Test
{
    public class MyShopUserManager<TUser> : UserManager<TUser>, IDisposable where TUser : class
{
    private readonly ITenantService tenantService;
    private readonly IUserRepository userRepository;
    public MyUserManager(IUserStore<TUser> store, IOptions<IdentityOptions> optionsAccessor,
        IPasswordHasher<TUser> passwordHasher, IEnumerable<IUserValidator<TUser>> userValidators,
        IEnumerable<IPasswordValidator<TUser>> passwordValidators, ILookupNormalizer keyNormalizer,
        IdentityErrorDescriber errors, IServiceProvider services, ILogger<UserManager<TUser>> logger,
        ITenantService tenantService, IUserRepository userRepository)
        : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
    {
        this.tenantService = tenantService;
        this.userRepository = userRepository;
    }
    public override async Task<TUser> FindByEmailAsync(string email)
    {
        ThrowIfDisposed();
        if (email == null)
        {
            throw new ArgumentNullException(nameof(email));
        }
        var users = (await userRepository.GetAllAsync()).Where(u => u.Email == email);
        if (users == null)
        {
            return null;
        }
        if (users.Count() == 1)
        {
            return await Store.FindByIdAsync(users.First().Id.ToString(), CancellationToken);
        }
        var currentDomain = tenantService.GetCurrentDomainAsync().Result;
        var user = users.SingleOrDefault(u => u.DomainId == currentDomain.Id);
        if (user == null)
        {
            return null;
        }
        return await Store.FindByIdAsync(user.Id.ToString(), CancellationToken);
    }
}
}

请注意,由于多域和生成的用户名,您应该使用 userManager.FindByEmailAsync,而不是 FindByNameAsync。

我必须创建自定义登录管理器来处理多域用户:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MultiShop.Core.Tenant;
using MultiShop.Data.Entities;
using System.Threading.Tasks;
namespace Test
{
public class MySignInManager : SignInManager<ApplicationUser>
{
    private readonly ITenantService tenantService;
    public MySignInManager(UserManager<ApplicationUser> userManager, IHttpContextAccessor contextAccessor,
        IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor,
        ILogger<SignInManager<ApplicationUser>> logger, IAuthenticationSchemeProvider schemes,
        ITenantService tenantService)
        : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes)
    {
        this.tenantService = tenantService;
    }
    public override async Task<SignInResult> PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure)
    {
        var currentDomain = await tenantService.GetCurrentDomainAsync();
        return await base.PasswordSignInAsync($"{userName}{currentDomain.Id}", password, isPersistent, lockoutOnFailure);
    }
}
}

最后,我必须将自定义管理器注册到 Asp.Net 核心标识 DI 中:

services
   .AddIdentity<ApplicationUser, ApplicationRole>()
   .AddEntityFrameworkStores<MultiShopDbContext>()
   .AddDefaultTokenProviders()
   //my custom managers for domain segmented users
   .AddUserManager<MyUserManager<ApplicationUser>>()
   .AddSignInManager<MySignInManager>();

就是这样!

相关内容

  • 没有找到相关文章

最新更新