• [从0到1搭建ABP微服务]


    一、简介#

    ABP模板项目中已经提供了租户登录和管理功能,但是模板项目是单体应用结构,无法单独部署租户服务,所以难以满足微服务的需求。本篇文章将会介绍搭建ABP租户管理服务,并单独部署应用。

    二、创建工程#

    2.1 创建TenantService.Host服务#

    微服务的开发应该是模块化的,所以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 引用依赖#

    租户服务关系的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完整代码如下:#

    Copy
    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 = 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<AbpLocalizationOptions>(options =>
                {
                    options.Languages.Add(new LanguageInfo("en", "en", "English"));
                });
    
                Configure<AbpDbContextOptions>(options =>
                {
                    options.UseSqlServer();
                });
    
                context.Services.AddStackExchangeRedisCache(options =>
                {
                    options.Configuration = configuration["Redis:Configuration"];
                });
    
                Configure<AbpAuditingOptions>(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<ICurrentPrincipalAccessor>();
                    var map = new Dictionary<string, string>()
                    {
                        { "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<IDataSeeder>()
                            .SeedAsync();
                    }
                });
            }
        }
    }
    

    五、管理租户#

    5.1 启动TenantService.Host服务#

    Ctrl+F5启动即可,启动成功后可以看到Swagger跳转。

    此时ABP已经将租户的权限种子数据添加到数据库。

    5.2 添加租户#

    使用POST请求添加Default租户

    请求成功并返回租户信息:

    此时ABP已经自动添加Dfault租户的admin用户、角色和权限。

    5.3 使用租户登录#

    在AuthServer中使用Default获取token

    可以看出租户已经启用并成功登录,而且token中已经包含tenant

    六、总结#

    ABP社区版中的租户功能有点弱,应付中小型项目是绰绰有余的,对于大型SaaS系统笔者还是建议购买商业版以获得更大的支持。ABP的租户还有更多的配置,如租户独立数据库等,在搭建成功租户服务后可以一步步尝试更多的ABP特性。

  • 相关阅读:
    一步步搭建自己的web服务器
    http协议知识整理
    数据库系统原理-第一章 数据库系统基本概念
    程序设计入门-C语言基础知识-翁恺-第七周:指针与字符串-详细笔记(七)
    程序设计入门-C语言基础知识-翁恺-第六周:数组-详细笔记(六)
    程序设计入门-C语言基础知识-翁恺-第五周:函数-详细笔记(五)
    程序设计入门-C语言基础知识-翁恺-期中测试
    程序设计入门-C语言基础知识-翁恺-第四周:循环控制-详细笔记(四)
    程序设计入门-C语言基础知识-翁恺-第三周:循环-详细笔记(三)
    程序设计入门-C语言基础知识-翁恺-第二周:简单的计算程序-详细笔记(二)
  • 原文地址:https://www.cnblogs.com/siyunianhua/p/14343166.html
Copyright © 2020-2023  润新知