如何在多租户环境中使用Asp.Net核心身份 [英] How to use Asp.Net Core Identity in Multi-Tenant environment

查看:89
本文介绍了如何在多租户环境中使用Asp.Net核心身份的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a working Asp.Net Core application with default Identity handling. Now I want to use it for multi domains. I extended ApplicationUser with DomainId. How can I handle not just username / email to authenticate / register the user, but also the current DomainId?

当用户注册,登录系统时,获取当前的DomainId并不是问题,我有一个正在运行的多租户Asp.Net Core系统.我仅在使用DomainId进行用户管理时遇到问题.

It's not a problem to get the current DomainId when the user is registering, logging into the system, I have a working multi-tenant Asp.Net Core system. I have issue only with user management with DomainId.

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

Is there any setting for this? What should I override to get this funcionality? For example UserStore, UserManager?

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

I found some tutorial for old Asp.Net Identity for example this: https://www.scottbrady91.com/ASPNET-Identity/Quick-and-Easy-ASPNET-Identity-Multitenancy But I couldn't find any tutorial for the new Asp.Net Core Identity.

推荐答案

最后我弄清楚了. 因此,首先,我必须将用户电子邮件设置为非唯一.旁注:我也使用电子邮件发送用户名,我不想向用户询问用户名:

Finally I figured it out. So first, I have to set user email to not unique. Sidenote: I'm using email for UserName also, I don't like to ask UserName from users:

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

当新用户注册自己时,我正在将当前域ID合并到UserName,这将帮助用户通过完全不同的域将具有相同Email/UserName的用户注册到系统中.

When a new user register himself, I'm merging current Domain Id to UserName, this helps users to register with same Email / UserName into the system through totally different domains.

然后,我必须创建我的自定义UserManager,在此我要覆盖FindByEmail:

Then I had to create my custom UserManager, where I'm overriding 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.

Be careful, because of multi-domains and generated UserNames, you should use userManager.FindByEmailAsync, instead of FindByNameAsync.

我必须创建自定义的SignInManager来处理多域用户:

I had to create custom SignInManager for handling multi-domain users:

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 Core Identity DI:

Finally I have to register my custom managers into Asp.Net Core Identity DI:

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

就是这样!

这篇关于如何在多租户环境中使用Asp.Net核心身份的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆