[从0到1搭建ABP微服务]|[从0到1搭建ABP微服务] - 搭建租户管理服务

一、简介 ABP模板项目中已经提供了租户登录和管理功能,但是模板项目是单体应用结构,无法单独部署租户服务,所以难以满足微服务的需求。本篇文章将会介绍搭建ABP租户管理服务,并单独部署应用。
二、创建工程 2.1 创建TenantService.Host服务 [从0到1搭建ABP微服务]|[从0到1搭建ABP微服务] - 搭建租户管理服务
文章图片

微服务的开发应该是模块化的,所以TenantService.Host服务名没有放在在ABP微服务解决方案中,选择独立搭建、独立部署的方式。
三、安装模块组件 在大型团队中或者小型精英团队中建议拉取将ABP源码发布本地Nuget包,所有服务引用本地包进行开发。因为无论ABP如何通用也是无法满足企业级后台业务的发展和版本迭代的,有老司机的团队应该要掌握修改ABP底层应用甚至底层框架的能力。
3.1 安装ids4、.net core、ABP等必须组件

  • Serilog.Extensions.Hosting Version="3.0.0"
  • Serilog.Sinks.File Version="4.0.0"
  • Serilog.Sinks.Elasticsearch Version="6.5.0"
  • Swashbuckle.AspNetCore Version="5.0.0-rc4"
  • IdentityServer4.AccessTokenValidation Version="3.0.0"
  • Microsoft.Extensions.Caching.StackExchangeRedis Version="3.1.0"
  • Microsoft.AspNetCore.DataProtection.StackExchangeRedis Version="3.1.0"
  • Volo.Abp.AspNetCore.MultiTenancy Version="2.0.1"
  • Volo.Abp.AuditLogging.EntityFrameworkCore Version="2.0.1"
  • Volo.Abp.Autofac Version="2.0.1"
  • Volo.Abp.EntityFrameworkCore.SqlServer Version="2.0.1"
  • Volo.Abp.PermissionManagement.EntityFrameworkCore Version="2.0.1"
  • Volo.Abp.SettingManagement.EntityFrameworkCore Version="2.0.1"
  • Volo.Abp.TenantManagement.Application Version="2.0.1"
  • Volo.Abp.TenantManagement.EntityFrameworkCore Version="2.0.1"
  • Volo.Abp.TenantManagement.HttpApi Version="2.0.1"
  • Volo.Abp.Identity.Application.Contracts Version="2.0.1"
  • Volo.Abp.Identity.EntityFrameworkCore Version="2.0.1"
  • volo.abp.identityserver.entityframeworkcore Version="2.0.1"
四、配置Module ABP不仅基于DDD设计,更是基于模块化实现的。
4.1 添加TenantServiceHostModule 在TenantService.Host根目录中添加TenantServiceHostModule
4.2 引用依赖 【[从0到1搭建ABP微服务]|[从0到1搭建ABP微服务] - 搭建租户管理服务】租户服务关系的ABP应用模块比较多,所以依赖也比其他服务多一些。ABP模块引用会在服务模块启动时载入IOC容器,这样的好处是无需多次引用,只要在Mudule中引用一次就可以。
引用的依赖顺序如下:
AbpAutofacModule
AbpEventBusRabbitMqModule
AbpAspNetCoreMultiTenancyModule
AbpEntityFrameworkCoreSqlServerModule
AbpAuditLoggingEntityFrameworkCoreModule
AbpPermissionManagementEntityFrameworkCoreModule
AbpSettingManagementEntityFrameworkCoreModule
AbpTenantManagementHttpApiModule
AbpTenantManagementEntityFrameworkCoreModule
AbpTenantManagementApplicationModule
AbpIdentityEntityFrameworkCoreModule
AbpIdentityServerEntityFrameworkCoreModule
4.3 注册服务 与其他服务一样需要注册认证、Swagger、默认语言、数据库服务、redis等,这里就不过多赘述了,ABP文档有详细的解释。
4.4 配置初始化模块 这里也跟其他服务一样,没有特殊的模块需要初始化。
4.5 TenantServiceHostModule完整代码如下:
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.DependencyInjection; using Microsoft.OpenApi.Models; using StackExchange.Redis; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using Volo.Abp; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.Auditing; using Volo.Abp.AuditLogging.EntityFrameworkCore; using Volo.Abp.Autofac; using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore.SqlServer; using Volo.Abp.EventBus.RabbitMq; using Volo.Abp.Identity; using Volo.Abp.Identity.EntityFrameworkCore; using Volo.Abp.IdentityServer.EntityFrameworkCore; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.PermissionManagement.EntityFrameworkCore; using Volo.Abp.Security.Claims; using Volo.Abp.SettingManagement.EntityFrameworkCore; using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement.EntityFrameworkCore; using Volo.Abp.Threading; namespace TenantService.Host { [DependsOn( typeof(AbpAutofacModule), typeof(AbpAspNetCoreMultiTenancyModule), typeof(AbpEntityFrameworkCoreSqlServerModule), typeof(AbpAuditLoggingEntityFrameworkCoreModule), typeof(AbpPermissionManagementEntityFrameworkCoreModule), typeof(AbpSettingManagementEntityFrameworkCoreModule), typeof(AbpTenantManagementHttpApiModule), typeof(AbpTenantManagementEntityFrameworkCoreModule), typeof(AbpTenantManagementApplicationModule), typeof(AbpIdentityEntityFrameworkCoreModule), typeof(AbpIdentityServerEntityFrameworkCoreModule) )] public class TenantServiceHostModule: AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); context.Services.AddAuthentication("Bearer") .AddIdentityServerAuthentication(options => { options.Authority = configuration["AuthServer:Authority"]; options.ApiName = configuration["AuthServer:ApiName"]; options.RequireHttpsMetadata = https://www.it610.com/article/false; }); context.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "Tenant Service API", Version = "v1" }); options.DocInclusionPredicate((docName, description) => true); options.CustomSchemaIds(type => type.FullName); }); Configure(options => { options.Languages.Add(new LanguageInfo("en", "en", "English")); }); Configure(options => { options.UseSqlServer(); }); context.Services.AddStackExchangeRedisCache(options => { options.Configuration = configuration["Redis:Configuration"]; }); Configure(options => { options.IsEnabledForGetRequests = true; options.ApplicationName = "TenantService"; }); var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); context.Services.AddDataProtection() .PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys"); }public override void OnApplicationInitialization(ApplicationInitializationContext context) { var app = context.GetApplicationBuilder(); app.UseCorrelationId(); app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); app.Use(async (ctx, next) => { var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); var map = new Dictionary() { { "sub", AbpClaimTypes.UserId }, { "role", AbpClaimTypes.Role }, { "email", AbpClaimTypes.Email }, }; var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); await next(); }); app.UseAbpRequestLocalization(); app.UseSwagger(); app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "Tenant Service API"); }); app.UseAuditing(); app.UseMvcWithDefaultRouteAndArea(); AsyncHelper.RunSync(async () => { using (var scope = context.ServiceProvider.CreateScope()) { await scope.ServiceProvider .GetRequiredService() .SeedAsync(); } }); } } }

五、管理租户 5.1 启动TenantService.Host服务 Ctrl+F5启动即可,启动成功后可以看到Swagger跳转。
[从0到1搭建ABP微服务]|[从0到1搭建ABP微服务] - 搭建租户管理服务
文章图片

此时ABP已经将租户的权限种子数据添加到数据库。
[从0到1搭建ABP微服务]|[从0到1搭建ABP微服务] - 搭建租户管理服务
文章图片

5.2 添加租户 使用POST请求添加Default租户
[从0到1搭建ABP微服务]|[从0到1搭建ABP微服务] - 搭建租户管理服务
文章图片

请求成功并返回租户信息:
[从0到1搭建ABP微服务]|[从0到1搭建ABP微服务] - 搭建租户管理服务
文章图片

此时ABP已经自动添加Dfault租户的admin用户、角色和权限。
5.3 使用租户登录 在AuthServer中使用Default获取token
[从0到1搭建ABP微服务]|[从0到1搭建ABP微服务] - 搭建租户管理服务
文章图片

可以看出租户已经启用并成功登录,而且token中已经包含tenant
[从0到1搭建ABP微服务]|[从0到1搭建ABP微服务] - 搭建租户管理服务
文章图片

六、总结 ABP社区版中的租户功能有点弱,应付中小型项目是绰绰有余的,对于大型SaaS系统笔者还是建议购买商业版以获得更大的支持。ABP的租户还有更多的配置,如租户独立数据库等,在搭建成功租户服务后可以一步步尝试更多的ABP特性。
文章目录:https://www.cnblogs.com/william-xu/p/12537155.html
代码地址:https://github.com/WilliamXu96/ABP-MicroService

    推荐阅读