X-Admin&ABP框架开发-租户管理

  软件即服务概念的推进,定制化到通用化的发展,用一套代码完成适应不一样企业的需求,利用多租户技术能够去作到这一点。ABP里提供了多租户这一律念而且也在Zero模块中实现了这一律念。java

 

1、多租户的概念

  单部署-单数据库:部署应用程序的单个实例和单个数据库。在每一个数据表(关系型数据库)里用一个TenantId(租户Id或相似的如企业Id)字段来隔离区分每一个租户数据。git

 

  单部署-多数据库:部署应用的单一实例,用一个主(宿主)数据库存储租户元数据(像租户名和子域),并为每一个租户创建并维护一个隔离的数据库。操做上经过识别当前租户并从主数据库中读取相对应的存储数据库地址,切换到该租户独有的数据库中执行操做。数据库

 

 

  多部署-多数据库:为每一个租户部署应用的一个实例并使用一个独立的数据库,那么咱们就能够在一台服务器上为多个租户服务,只需确保相同应用的多个实例在一个服务器的环境下不会互相冲突就行。服务器

 

  还有两种多租户形式,诸如单部署-混搭数据库、集群部署-单/多/混搭数据库,再也不说起,ABP针对于这五种多租户形式均可以使用。cookie

 

  宿主与租户:对于这两个概念,最好的理解方式即是酒店,酒店老板便是宿主,租户只拥有房间权限,酒店老板能够提供管理全部租户和房间。ide

 

2、ABP中多租户配置

一、启用/禁用多租户网站

  若是不须要多租户,好比说没有多租户情形,应用部署在企业私有服务器上,那么也能够不考虑多租户的使用,能够在ABP中关闭多租户(尽管关闭了,但默认仍是会使用一个租户,默认租户Id为1,此时只有这个默认租户没有宿主)。在WebCoreModule中PreInitialize方法内能够添加以下代码启用或关闭多租户,默认是启用的。spa

public override void PreInitialize()
{
   ...

    Configuration.MultiTenancy.IsEnabled = true;

    ...
}

 

二、侦测当前租户并在Session中获取租户3d

 ABP中租户名称是惟一的,对于识别当前租户或是宿主身份,ABP没有使用Asp.Net 提供的Session,声明了IAbpSession接口并提供了默认的实现(ClaimAbpSession)去测定当前租户信息,按照以下思路去肯定租户。code

  • 若是当前用户登陆了系统,那么能够从当前用户的声明信息中读取到当前租户信息,若是没有读取到租户信息,那么能够判定是宿主。
  • 若是当前用户没有登陆系统,那么会有几种方式去获取,若是如下几种方式仍未获取到租户Id,则认为是使用宿主登陆。
  • 从当前域名或是子域名去获取域名名称,而后经过租户仓储去查询是否存在相关的域名或子域名存在则能够肯定租户Id。
  • 从Http请求头中获取在ABP中默认配置项Abp.TenantId(该配置项可更换名称)。
  • 从Http请求的cookie中获取Abp.TenantId

 IAbpSession声明了获取当前用户和租户信息的方法,该方法容许咱们获取当前登陆的用户及当前的租户信息。而且获取到的信息按照不一样的规则,有着不一样的做用。

  • 若是获取到的用户和租户Id都是空的,那么意味着当前用户没有登陆系统,所以也没法判定出当前是宿主仍是租户。
  • 若是用户Id是空的,可是租户Id不是空的,那么能够知道是哪一个租户,可是用户仍然是没有登陆的,只是选择了租户。
  • 若是用户Id不是空的,可是租户Id是空的,那么能够知道是用户使用宿主登陆了系统。
  • 若是用户Id且租户Id不是空的,那么就知道是选择了租户而且是租户中的某个用户登陆了系统。

 

三、数据过滤

  若是使用了多租户,那么在读取数据时,会依据当前租户Id加上额外的过滤条件,这一点ABP已经处理好了,咱们无需在linq中敲代码,可是有个前提条件是,读取数据的这个实体有设置多租户。

  一、若是实体使用的是IMustHaveTenant接口,那么读取时会依照当前租户Id进行条件过滤。

  二、若是实体使用的是IMayHaveTenant接口,那么读取到的数据会依照当前租户Id的有无值进行区分,若是当前租户Id为空,那么将读取到宿主的数据,若是租户Id不为空,则读取相应租户数据。

  三、若是实体没使用这两个接口,则读取到的数据不区分宿主和租户。

  这两个接口使用场景:若是是宿主和租户都须要的,好比角色、用户、部门等,那么使用IMayHaveTenant接口,若是仅是租户所须要的那只需使用IMustHaveTenant接口。

 

四、宿主与租户间切换

  此处切换能够这么理解,给我一个其它租户Id,我能够在个人租户中获取到其它租户的数据,相应的,其它租户也能够获取到我租户的数据,或是宿主获取租户数据。若是不给定租户Id,租户能够获取宿主数据。

public class ProductService : ITransientDependency
{
    private readonly IRepository<Product> _productRepository;
    private readonly IUnitOfWorkManager _unitOfWorkManager;

    public ProductService(IRepository<Product> productRepository, IUnitOfWorkManager unitOfWorkManager)
    {
        _productRepository = productRepository;
        _unitOfWorkManager = unitOfWorkManager;
    }

    [UnitOfWork]
    public virtual List<Product> GetProducts(int tenantId)
    {
        using (_unitOfWorkManager.Current.SetTenantId(tenantId))
        {
            return _productRepository.GetAllList();
        }
    }
}

 

3、配置一个多租户实体

  基于以前的数据字典进行改造,以便适用于多个租户使用,而且考虑到宿主无需使用数据字典,将其继承IMustHaveTenant接口后,更新数据库即可。

public class DataDictionary : Entity<long>, IMustHaveTenant
{
    public const int MaxNameLength = 30;

    /// <summary>
    /// 租户Id
    /// </summary>
    public int? TenantId { get; set; }

    /// <summary>
    /// 字典类型
    /// </summary>
    [StringLength(MaxNameLength)]
    public string TypeName { get; set; }

    /// <summary>
    /// 关联数据字典项
    /// </summary>
    public virtual ICollection<DataDictionaryItem> DataDictionaryItem { get; set; }
}

   我设置了默认当前租户,而且不提供选择租户的页面,经过Url去区分宿主和默认租户,登陆当前租户帐号后,查看当前网站内的数据字典看到以前已有数据所有消失,获取数据字典数据时,默认是ABP将当前租户Id带入做为查询条件了。

  

 

   修改添加方法,添加当前租户Id的赋值,再次为当前租户添加几条相应的数据字典,页面中便可存在相关数据了。

dataDictionary.TenantId = AbpSession.TenantId.Value;

   最后两条数据是指定租户Id为1下的,以前的数据能够手动清除。

   

 至此,对于ABP中租户的相关使用了解的清楚了,对于多租户下数据存储量大,拆分红集群部署-多数据库情形没有作尝试,但愿有机会可使用一番。

 

 仓库地址:https://gitee.com/530521314/Partner.Surround.git

2020-01-11,望技术有成后能回来看见本身的脚步
相关文章
相关标签/搜索