ABP微服务系列学习-搭建自己的微服务结构(三)

上一篇我们基础服务初步搭建完毕,接下来我们整一下认证和网关。

搭建认证服务

认证服务的话,ABP CLI生成的所有模板都包括了一个AuthServer。我们直接生成模板然后微调一下就可以直接用了。

abp new FunShow -t app --tiered 

使用命令创建模板后,我们可以找到一个AuthServer。把项目移动到Apps目录下,然后我们开始改造一下这个项目。
首先修改项目文件的引用配置
修改EFCore项目引用为AdministrationService.EntityFrameworkCore和IdentityService.EntityFrameworkCore,
然后添加Shared.Localization和Shared.Hosting.AspNetCore项目引用,别的基本不用怎么修改,完整项目配置为:

<Project Sdk="Microsoft.NET.Sdk.Web">    <Import Project="........common.props" />    <PropertyGroup>     <TargetFramework>net7.0</TargetFramework>     <UserSecretsId>b83bc18b-a6ca-4e2d-a827-26ffaff35dce</UserSecretsId>     <DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>     <DockerfileContext>........</DockerfileContext>   </PropertyGroup>    <ItemGroup>     <PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="6.0.5" />     <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" />   </ItemGroup>    <ItemGroup>     <PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" Version="7.0.0" />     <PackageReference Include="Volo.Abp.EventBus.RabbitMQ" Version="7.0.0" />     <PackageReference Include="Volo.Abp.BackgroundJobs.RabbitMQ" Version="7.0.0" />     <PackageReference Include="Volo.Abp.Account.Web.OpenIddict" Version="7.0.0" />     <PackageReference Include="Volo.Abp.Account.Application" Version="7.0.0" />     <PackageReference Include="Volo.Abp.Account.HttpApi" Version="7.0.0" />   </ItemGroup>    <ItemGroup>     <ProjectReference Include="........servicesadministrationsrcFunShow.AdministrationService.EntityFrameworkCoreFunShow.AdministrationService.EntityFrameworkCore.csproj" />     <ProjectReference Include="........servicesidentitysrcFunShow.IdentityService.EntityFrameworkCoreFunShow.IdentityService.EntityFrameworkCore.csproj" />     <ProjectReference Include="........sharedFunShow.Shared.Hosting.AspNetCoreFunShow.Shared.Hosting.AspNetCore.csproj" />     <ProjectReference Include="........sharedFunShow.Shared.LocalizationFunShow.Shared.Localization.csproj" />   </ItemGroup>    <ItemGroup>     <PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="2.0.0-*" />   </ItemGroup>    <ItemGroup>     <Compile Remove="Logs**" />     <Content Remove="Logs**" />     <EmbeddedResource Remove="Logs**" />     <None Remove="Logs**" />   </ItemGroup>  </Project>  

然后修改Program文件,主要是日志配置修改一下,别的不用改动

using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using FunShow.Shared.Hosting.AspNetCore; using Serilog;  namespace FunShow.AuthServer;  public class Program {     public async static Task<int> Main(string[] args)     {         var assemblyName = typeof(Program).Assembly.GetName().Name;          SerilogConfigurationHelper.Configure(assemblyName);          try         {             Log.Information($"Starting {assemblyName}.");             var builder = WebApplication.CreateBuilder(args);             builder.Host                 .AddAppSettingsSecretsJson()                 .UseAutofac()                 .UseSerilog();             await builder.AddApplicationAsync<FunShowAuthServerModule>();             var app = builder.Build();             await app.InitializeApplicationAsync();             await app.RunAsync();             return 0;         }         catch (Exception ex)         {             Log.Fatal(ex, $"{assemblyName} terminated unexpectedly!");             return 1;         }         finally         {             Log.CloseAndFlush();         }     } }  

修改module.cs

using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography.X509Certificates; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using FunShow.AdministrationService.EntityFrameworkCore; using FunShow.IdentityService.EntityFrameworkCore; using FunShow.Shared.Hosting.AspNetCore; using Prometheus; using StackExchange.Redis; using Volo.Abp; using Volo.Abp.Account; using Volo.Abp.Account.Web; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite; using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; using Volo.Abp.Auditing; using Volo.Abp.BackgroundJobs.RabbitMQ; using Volo.Abp.Caching; using Volo.Abp.Caching.StackExchangeRedis; using Volo.Abp.Emailing; using Volo.Abp.EventBus.RabbitMq; using Volo.Abp.Modularity; using Volo.Abp.MultiTenancy; using Volo.Abp.OpenIddict; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.VirtualFileSystem; using Microsoft.AspNetCore.HttpOverrides; using FunShow.Shared.Localization;  namespace FunShow.AuthServer;  [DependsOn(     typeof(AbpCachingStackExchangeRedisModule),     typeof(AbpEventBusRabbitMqModule),     typeof(AbpBackgroundJobsRabbitMqModule),     typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule),     typeof(AbpAccountWebOpenIddictModule),     typeof(AbpAccountApplicationModule),     typeof(AbpAccountHttpApiModule),     typeof(AdministrationServiceEntityFrameworkCoreModule),     typeof(IdentityServiceEntityFrameworkCoreModule),     typeof(FunShowSharedHostingAspNetCoreModule),     typeof(FunShowSharedLocalizationModule) )] public class FunShowAuthServerModule : AbpModule {     public override void PreConfigureServices(ServiceConfigurationContext context)     {         var hostingEnvironment = context.Services.GetHostingEnvironment();         var configuration = context.Services.GetConfiguration();          PreConfigure<OpenIddictBuilder>(builder =>     {     	builder.AddValidation(options =>     {     options.AddAudiences("AccountService");     options.UseLocalServer();     options.UseAspNetCore();     });     });     if (!hostingEnvironment.IsDevelopment())     {     	PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>     	{     	options.AddDevelopmentEncryptionAndSigningCertificate = false;     	});              PreConfigure<OpenIddictServerBuilder>(builder =>         {             builder.AddSigningCertificate(GetSigningCertificate(hostingEnvironment, configuration));             builder.AddEncryptionCertificate(GetSigningCertificate(hostingEnvironment, configuration));             });         }     }          public override void ConfigureServices(ServiceConfigurationContext context)     {     //You can disable this setting in production to avoid any potential security risks.         Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;                  var hostingEnvironment = context.Services.GetHostingEnvironment();         var configuration = context.Services.GetConfiguration();                  ConfigureBundles();         ConfigureSwagger(context, configuration);         ConfigureSameSiteCookiePolicy(context);         ConfigureExternalProviders(context);                  Configure<AbpMultiTenancyOptions>(options =>         {         	options.IsEnabled = true;         });                  Configure<AbpAuditingOptions>(options =>         {             options.ApplicationName = "AuthServer";         });                  Configure<AppUrlOptions>(options =>         {             options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];             options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"].Split(','));         });                  Configure<AbpDistributedCacheOptions>(options =>         {         	options.KeyPrefix = "FunShow:";         });                  var dataProtectionBuilder = context.Services.AddDataProtection().SetApplicationName("FunShow");         var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]);         dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, "FunShow-Protection-Keys");                  context.Services.AddCors(options =>         {         	options.AddDefaultPolicy(builder =>             {             builder             .WithOrigins(             configuration["App:CorsOrigins"]             .Split(",", StringSplitOptions.RemoveEmptyEntries)             .Select(o => o.Trim().RemovePostFix("/"))             .ToArray()             )             .WithAbpExposedHeaders()             .SetIsOriginAllowedToAllowWildcardSubdomains()             .AllowAnyHeader()             .AllowAnyMethod()             .AllowCredentials();             });         });                  #if DEBUG         context.Services.Replace(ServiceDescriptor.Singleton<IEmailSender, NullEmailSender>());         #endif                  if (hostingEnvironment.IsDevelopment())         {             Configure<AbpVirtualFileSystemOptions>(options =>             {             options.FileSets.ReplaceEmbeddedByPhysical<FunShowSharedLocalizationModule>(Path.Combine(             hostingEnvironment.ContentRootPath,             $"..{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}..{Path.DirectorySeparatorChar}shared{Path.DirectorySeparatorChar}FunShow.Shared.Localization"));             });         }     }          public override void OnApplicationInitialization(ApplicationInitializationContext context)     {         var app = context.GetApplicationBuilder();         var env = context.GetEnvironment();                  var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();                  if (env.IsDevelopment())         {         	app.UseDeveloperExceptionPage();         }              app.UseAbpRequestLocalization();                  if (!env.IsDevelopment())         {         	app.UseErrorPage();         }         var forwardOptions = new ForwardedHeadersOptions         {             ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,             RequireHeaderSymmetry = false         };              forwardOptions.KnownNetworks.Clear();         forwardOptions.KnownProxies.Clear();              // ref: https://github.com/aspnet/Docs/issues/2384         app.UseForwardedHeaders(forwardOptions);                  app.UseCorrelationId();         app.UseAbpSecurityHeaders();         app.UseStaticFiles();         app.UseRouting();         app.UseCors();         app.UseCookiePolicy();         app.UseHttpMetrics();         app.UseAuthentication();         app.UseAbpOpenIddictValidation();         app.UseAbpSerilogEnrichers();         app.UseUnitOfWork();         app.UseAuthorization();         app.UseSwagger();         app.UseAbpSwaggerUI(options =>         {             options.SwaggerEndpoint("/swagger/v1/swagger.json", "Account Service API");             options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]);         });         	app.UseAuditing();         	app.UseConfiguredEndpoints(endpoints =>             {             	endpoints.MapMetrics();             });     }          private void ConfigureBundles()     {         Configure<AbpBundlingOptions>(options =>         {             options.StyleBundles.Configure(             LeptonXLiteThemeBundles.Styles.Global,             bundle =>             {             	bundle.AddFiles("/global-styles.css");             }         );         });     }          private void ConfigureExternalProviders(ServiceConfigurationContext context)     {     	context.Services.AddAuthentication();     }          private X509Certificate2 GetSigningCertificate(IWebHostEnvironment hostingEnv, IConfiguration configuration)     {         var fileName = "authserver.pfx";         var passPhrase = "2D7AA457-5D33-48D6-936F-C48E5EF468ED";         var file = Path.Combine(hostingEnv.ContentRootPath, fileName);                  if (!File.Exists(file))         {         	throw new FileNotFoundException($"Signing Certificate couldn't found: {file}");         }          	return new X509Certificate2(file, passPhrase);     }          private void ConfigureSwagger(ServiceConfigurationContext context, IConfiguration configuration)     {         SwaggerConfigurationHelper.ConfigureWithAuth(         context: context,         authority: configuration["AuthServer:Authority"],         scopes: new Dictionary<string, string> {         /* Requested scopes for authorization code request and descriptions for swagger UI only */         { "AccountService", "Account Service API" }         },         apiTitle: "Account Service API"         );     }          private void ConfigureSameSiteCookiePolicy(ServiceConfigurationContext context)     {     	context.Services.AddSameSiteCookiePolicy();     } }  

最后修改配置文件

{   "App": {     "SelfUrl": "https://localhost:44322",     "CorsOrigins": "http://localhost:4200,http://localhost:9527,https://localhost:44307,https://localhost:44325,https://localhost:44353,https://localhost:44367,https://localhost:44388,https://localhost:44381,https://localhost:44361",     "RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307,https://localhost:44321,http://localhost:9527"   },   "AuthServer": {     "Authority": "https://localhost:44322",     "RequireHttpsMetadata": "true",     "SwaggerClientId": "WebGateway_Swagger"   },   "Logging": {     "LogLevel": {       "Default": "Information",       "Microsoft": "Warning",       "Microsoft.Hosting.Lifetime": "Information"     }   },   "AllowedHosts": "*",   "ConnectionStrings": {     "AdministrationService": "Host=localhost;Port=5432;User ID=postgres;password=myPassw0rd;Pooling=true;Database=FunShow_Administration;",     "IdentityService": "Host=localhost;Port=5432;User ID=postgres;password=myPassw0rd;Pooling=true;Database=FunShow_Identity;"   },   "StringEncryption": {     "DefaultPassPhrase": "fCrJICTG3WoyissG"   },   "Redis": {     "Configuration": "localhost:6379"   },   "RabbitMQ": {     "Connections": {       "Default": {         "HostName": "localhost"       }     },     "EventBus": {       "ClientName": "FunShow_AuthServer",       "ExchangeName": "FunShow"     }   },   "ElasticSearch": {     "Url": "http://localhost:9200"   } }  

这样我们认证服务即修改完成。

搭建网关服务

网关服务我们直接新建一个空asp.net core项目。
然后只需要添加一个我们的Shared.Hosting.Gateways项目引用即可。

<Project Sdk="Microsoft.NET.Sdk.Web">    <Import Project="........common.props" />    <PropertyGroup>     <TargetFramework>net7.0</TargetFramework>   </PropertyGroup>    <ItemGroup>     <ProjectReference Include="........sharedFunShow.Shared.Hosting.GatewaysFunShow.Shared.Hosting.Gateways.csproj" />   </ItemGroup>    <ItemGroup>     <Compile Remove="Logs**" />     <Content Remove="Logs**" />     <EmbeddedResource Remove="Logs**" />     <None Remove="Logs**" />   </ItemGroup>  </Project>  

修改Program.cs

using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using FunShow.Shared.Hosting.AspNetCore; using Serilog;  namespace FunShow.WebGateway;  public class Program {     public async static Task<int> Main(string[] args)     {         var assemblyName = typeof(Program).Assembly.GetName().Name;          SerilogConfigurationHelper.Configure(assemblyName);          try         {             Log.Information($"Starting {assemblyName}.");             var builder = WebApplication.CreateBuilder(args);             builder.Host                 .AddAppSettingsSecretsJson()                 .AddYarpJson()                 .UseAutofac()                 .UseSerilog();             await builder.AddApplicationAsync<FunShowWebGatewayModule>();             var app = builder.Build();             await app.InitializeApplicationAsync();             await app.RunAsync();             return 0;         }         catch (Exception ex)         {             Log.Fatal(ex, $"{assemblyName} terminated unexpectedly!");             return 1;         }         finally         {             Log.CloseAndFlush();         }     } }  

这里和认证服务基本一致,就是多了一个AddYarpJson()来添加我们的yarp的配置文件。
在目录下新建yarp.json文件,添加我们的yarp配置内容。配置集群和路由如下:

{   "ReverseProxy": {     "Routes": {       "Account Service": {         "ClusterId": "accountCluster",         "Match": {           "Path": "/api/account/{**everything}"         }       },       "Identity Service": {         "ClusterId": "identityCluster",         "Match": {           "Path": "/api/identity/{**everything}"         }       },       "Administration Service": {         "ClusterId": "administrationCluster",         "Match": {           "Path": "/api/abp/{**everything}"         }       },       "Logging Service": {         "ClusterId": "loggingCluster",         "Match": {           "Path": "/api/LoggingService/{**everything}"         }       },       "feature-management-route": {         "ClusterId": "feature-management-cluster",         "Match": {           "Path": "/api/feature-management/{**everything}"         }       },       "permission-management-route": {         "ClusterId": "permission-management-cluster",         "Match": {           "Path": "/api/permission-management/{**everything}"         }       },       "setting-management-route": {         "ClusterId": "setting-management-cluster",         "Match": {           "Path": "/api/setting-management/{**everything}"         }       }     },     "Clusters": {       "accountCluster": {         "Destinations": {           "destination1": {             "Address": "https://localhost:44322"           }         }       },       "identityCluster": {         "Destinations": {           "destination1": {             "Address": "https://localhost:44388"           }         }       },       "administrationCluster": {         "Destinations": {           "destination1": {             "Address": "https://localhost:44367"           }         }       },       "loggingCluster": {         "Destinations": {           "destination1": {             "Address": "https://localhost:45124"           }         }       },       "feature-management-cluster": {         "Destinations": {           "destination1": {             "Address": "https://localhost:44367"           }         }       },       "permission-management-cluster": {         "Destinations": {           "destination1": {             "Address": "https://localhost:44367"           }         }       },       "setting-management-cluster": {         "Destinations": {           "destination1": {             "Address": "https://localhost:44367"           }         }       }     }   } } 

在appsettings.json文件添加我们认证服务的地址

{   "App": {     "SelfUrl": "https://localhost:44325",     "CorsOrigins": "http://localhost:4200,https://localhost:44307,http://localhost:9527"   },   "AuthServer": {     "Authority": "https://localhost:44322",     "RequireHttpsMetadata": "true",     "SwaggerClientId": "WebGateway_Swagger"   },   "Logging": {     "LogLevel": {       "Default": "Information",       "Microsoft": "Warning",       "Microsoft.Hosting.Lifetime": "Information"     }   },   "AllowedHosts": "*",   "Redis": {     "Configuration": "localhost:6379"   },   "ElasticSearch": {     "Url": "http://localhost:9200"   } }  

最后我们添加FunShowWebGatewayModule文件。配置我们yarp的服务。

using System; using System.Collections.Generic; using System.Linq; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Rewrite; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using FunShow.Shared.Hosting.AspNetCore; using FunShow.Shared.Hosting.Gateways; using Volo.Abp; using Volo.Abp.Modularity;  namespace FunShow.WebGateway;  [DependsOn(     typeof(FunShowSharedHostingGatewaysModule) )] public class FunShowWebGatewayModule : AbpModule {     public override void ConfigureServices(ServiceConfigurationContext context)     {         // Enable if you need hosting environment         // var hostingEnvironment = context.Services.GetHostingEnvironment();         var configuration = context.Services.GetConfiguration();         var hostingEnvironment = context.Services.GetHostingEnvironment();                  SwaggerConfigurationHelper.ConfigureWithAuth(             context: context,             authority: configuration["AuthServer:Authority"],             scopes: new             Dictionary<string, string> /* Requested scopes for authorization code request and descriptions for swagger UI only */ {             { "AccountService", "Account Service API" },             { "IdentityService", "Identity Service API" },             { "AdministrationService", "Administration Service API" },             { "LoggingService", "Logging Service API" }             },             apiTitle: "Web Gateway API"         );                  context.Services.AddCors(options =>         {         	options.AddDefaultPolicy(builder =>         {         builder             .WithOrigins(                 configuration["App:CorsOrigins"]                 .Split(",", StringSplitOptions.RemoveEmptyEntries)                 .Select(o => o.Trim().RemovePostFix("/"))                 .ToArray()             )             .WithAbpExposedHeaders()             .SetIsOriginAllowedToAllowWildcardSubdomains()             .AllowAnyHeader()             .AllowAnyMethod()             .AllowCredentials();             });         });     }      public override void OnApplicationInitialization(ApplicationInitializationContext context)     {         var app = context.GetApplicationBuilder();         var env = context.GetEnvironment();                  if (env.IsDevelopment())         {         	app.UseDeveloperExceptionPage();         }         app.UseCorrelationId();         app.UseAbpSerilogEnrichers();         app.UseCors();         app.UseSwaggerUIWithYarp(context);                  app.UseRewriter(new RewriteOptions()             // Regex for "", "/" and "" (whitespace)             .AddRedirect("^(|\|\s+)$", "/swagger"));                      app.UseRouting();         app.UseEndpoints(endpoints =>         {         	endpoints.MapReverseProxy();         });     } }  

UseSwaggerUIWithYarp是从我们Yarp配置文件中读取服务信息去构造swagger路由配置。
好了,到这我们认证服务和网关服务也搭建完毕,下一篇我们开始迁移数据库。

发表评论

相关文章