临河任务调度
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

382 lines
14KB

  1. using System;
  2. using System.IO;
  3. using Blazorise.Bootstrap5;
  4. using Blazorise.Icons.FontAwesome;
  5. using Medallion.Threading;
  6. using Medallion.Threading.Redis;
  7. using Microsoft.AspNetCore.Authentication.Cookies;
  8. using Microsoft.AspNetCore.Authentication.OpenIdConnect;
  9. using Microsoft.AspNetCore.Builder;
  10. using Microsoft.AspNetCore.DataProtection;
  11. using Microsoft.AspNetCore.Hosting;
  12. using Microsoft.Extensions.Configuration;
  13. using Microsoft.Extensions.DependencyInjection;
  14. using Microsoft.Extensions.Hosting;
  15. using Microsoft.Extensions.Options;
  16. using Microsoft.IdentityModel.Protocols.OpenIdConnect;
  17. using Microsoft.OpenApi.Models;
  18. using Acme.BookStore.Blazor.WebApp.Tiered.Client;
  19. using Acme.BookStore.Blazor.WebApp.Tiered.Client.Menus;
  20. using Acme.BookStore.Blazor.WebApp.Tiered.Components;
  21. using Acme.BookStore.Blazor.WebApp.Tiered.Menus;
  22. using Acme.BookStore.Localization;
  23. using Acme.BookStore.MultiTenancy;
  24. using StackExchange.Redis;
  25. using Volo.Abp;
  26. using Volo.Abp.AspNetCore.Authentication.OpenIdConnect;
  27. using Volo.Abp.AspNetCore.Components.Web;
  28. using Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme;
  29. using Volo.Abp.AspNetCore.Components.Server.LeptonXLiteTheme.Bundling;
  30. using Volo.Abp.AspNetCore.Components.Web.Theming.Routing;
  31. using Volo.Abp.AspNetCore.Mvc.Client;
  32. using Volo.Abp.AspNetCore.Mvc.Localization;
  33. using Volo.Abp.AspNetCore.Mvc.UI;
  34. using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap;
  35. using Volo.Abp.AspNetCore.Mvc.UI.Bundling;
  36. using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;
  37. using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite;
  38. using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling;
  39. using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
  40. using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars;
  41. using Volo.Abp.AspNetCore.Serilog;
  42. using Volo.Abp.Autofac;
  43. using Volo.Abp.AutoMapper;
  44. using Volo.Abp.Caching;
  45. using Volo.Abp.Caching.StackExchangeRedis;
  46. using Volo.Abp.DistributedLocking;
  47. using Volo.Abp.Http.Client.IdentityModel.Web;
  48. using Volo.Abp.Identity.Blazor.Server;
  49. using Volo.Abp.Modularity;
  50. using Volo.Abp.MultiTenancy;
  51. using Volo.Abp.Security.Claims;
  52. using Volo.Abp.SettingManagement.Blazor.Server;
  53. using Volo.Abp.Swashbuckle;
  54. using Volo.Abp.TenantManagement.Blazor.Server;
  55. using Volo.Abp.UI;
  56. using Volo.Abp.UI.Navigation;
  57. using Volo.Abp.UI.Navigation.Urls;
  58. using Volo.Abp.VirtualFileSystem;
  59. namespace Acme.BookStore.Blazor.WebApp.Tiered;
  60. [DependsOn(
  61. typeof(BookStoreHttpApiClientModule),
  62. typeof(AbpCachingStackExchangeRedisModule),
  63. typeof(AbpDistributedLockingModule),
  64. typeof(AbpAspNetCoreMvcClientModule),
  65. typeof(AbpAspNetCoreAuthenticationOpenIdConnectModule),
  66. typeof(AbpHttpClientIdentityModelWebModule),
  67. typeof(AbpAspNetCoreComponentsServerLeptonXLiteThemeModule),
  68. typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule),
  69. typeof(AbpAutofacModule),
  70. typeof(AbpSwashbuckleModule),
  71. typeof(AbpAspNetCoreSerilogModule),
  72. typeof(AbpIdentityBlazorServerModule),
  73. typeof(AbpTenantManagementBlazorServerModule),
  74. typeof(AbpSettingManagementBlazorServerModule)
  75. )]
  76. public class BookStoreBlazorModule : AbpModule
  77. {
  78. public override void PreConfigureServices(ServiceConfigurationContext context)
  79. {
  80. context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
  81. {
  82. options.AddAssemblyResource(
  83. typeof(BookStoreResource),
  84. typeof(BookStoreDomainSharedModule).Assembly,
  85. typeof(BookStoreApplicationContractsModule).Assembly,
  86. typeof(BookStoreBlazorModule).Assembly
  87. );
  88. });
  89. PreConfigure<AbpAspNetCoreComponentsWebOptions>(options =>
  90. {
  91. options.IsBlazorWebApp = true;
  92. });
  93. }
  94. public override void ConfigureServices(ServiceConfigurationContext context)
  95. {
  96. var hostingEnvironment = context.Services.GetHostingEnvironment();
  97. var configuration = context.Services.GetConfiguration();
  98. // Add services to the container.
  99. context.Services.AddRazorComponents()
  100. .AddInteractiveServerComponents()
  101. .AddInteractiveWebAssemblyComponents();
  102. ConfigureUrls(configuration);
  103. ConfigureCache();
  104. ConfigureBundles();
  105. ConfigureMultiTenancy();
  106. ConfigureAuthentication(context, configuration);
  107. ConfigureAutoMapper();
  108. ConfigureVirtualFileSystem(hostingEnvironment);
  109. ConfigureBlazorise(context);
  110. ConfigureRouter(context);
  111. ConfigureMenu(configuration);
  112. ConfigureDataProtection(context, configuration, hostingEnvironment);
  113. ConfigureDistributedLocking(context, configuration);
  114. ConfigureSwaggerServices(context.Services);
  115. }
  116. private void ConfigureUrls(IConfiguration configuration)
  117. {
  118. Configure<AppUrlOptions>(options =>
  119. {
  120. options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"];
  121. });
  122. }
  123. private void ConfigureCache()
  124. {
  125. Configure<AbpDistributedCacheOptions>(options =>
  126. {
  127. options.KeyPrefix = "BookStore:";
  128. });
  129. }
  130. private void ConfigureBundles()
  131. {
  132. Configure<AbpBundlingOptions>(options =>
  133. {
  134. // MVC UI
  135. options.StyleBundles.Configure(
  136. LeptonXLiteThemeBundles.Styles.Global,
  137. bundle =>
  138. {
  139. bundle.AddFiles("/global-styles.css");
  140. }
  141. );
  142. //BLAZOR UI
  143. options.StyleBundles.Configure(
  144. BlazorLeptonXLiteThemeBundles.Styles.Global,
  145. bundle =>
  146. {
  147. bundle.AddFiles("/blazor-global-styles.css");
  148. //You can remove the following line if you don't use Blazor CSS isolation for components
  149. bundle.AddFiles(new BundleFile("/Acme.BookStore.Blazor.WebApp.Tiered.Client.styles.css", true));
  150. }
  151. );
  152. });
  153. }
  154. private void ConfigureMultiTenancy()
  155. {
  156. Configure<AbpMultiTenancyOptions>(options =>
  157. {
  158. options.IsEnabled = MultiTenancyConsts.IsEnabled;
  159. });
  160. }
  161. private void ConfigureAuthentication(ServiceConfigurationContext context, IConfiguration configuration)
  162. {
  163. context.Services.AddAuthentication(options =>
  164. {
  165. options.DefaultScheme = "Cookies";
  166. options.DefaultChallengeScheme = "oidc";
  167. })
  168. .AddCookie("Cookies", options =>
  169. {
  170. options.ExpireTimeSpan = TimeSpan.FromDays(365);
  171. options.IntrospectAccessToken();
  172. })
  173. .AddAbpOpenIdConnect("oidc", options =>
  174. {
  175. options.Authority = configuration["AuthServer:Authority"];
  176. options.RequireHttpsMetadata = configuration.GetValue<bool>("AuthServer:RequireHttpsMetadata");
  177. options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
  178. options.ClientId = configuration["AuthServer:ClientId"];
  179. options.ClientSecret = configuration["AuthServer:ClientSecret"];
  180. options.SaveTokens = true;
  181. options.GetClaimsFromUserInfoEndpoint = true;
  182. options.Scope.Add("roles");
  183. options.Scope.Add("email");
  184. options.Scope.Add("phone");
  185. options.Scope.Add("BookStore");
  186. });
  187. /*
  188. * This configuration is used when the AuthServer is running on the internal network such as docker or k8s.
  189. * Configuring the redirecting URLs for internal network and the web
  190. * The login and the logout URLs are configured to redirect to the AuthServer real DNS for browser.
  191. * The token acquired and validated from the the internal network AuthServer URL.
  192. */
  193. if (configuration.GetValue<bool>("AuthServer:IsContainerized"))
  194. {
  195. context.Services.Configure<OpenIdConnectOptions>("oidc", options =>
  196. {
  197. options.TokenValidationParameters.ValidIssuers = new[]
  198. {
  199. configuration["AuthServer:MetaAddress"]!.EnsureEndsWith('/'),
  200. configuration["AuthServer:Authority"]!.EnsureEndsWith('/')
  201. };
  202. options.MetadataAddress = configuration["AuthServer:MetaAddress"]!.EnsureEndsWith('/') +
  203. ".well-known/openid-configuration";
  204. var previousOnRedirectToIdentityProvider = options.Events.OnRedirectToIdentityProvider;
  205. options.Events.OnRedirectToIdentityProvider = async ctx =>
  206. {
  207. // Intercept the redirection so the browser navigates to the right URL in your host
  208. ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"]!.EnsureEndsWith('/') + "connect/authorize";
  209. if (previousOnRedirectToIdentityProvider != null)
  210. {
  211. await previousOnRedirectToIdentityProvider(ctx);
  212. }
  213. };
  214. var previousOnRedirectToIdentityProviderForSignOut = options.Events.OnRedirectToIdentityProviderForSignOut;
  215. options.Events.OnRedirectToIdentityProviderForSignOut = async ctx =>
  216. {
  217. // Intercept the redirection for signout so the browser navigates to the right URL in your host
  218. ctx.ProtocolMessage.IssuerAddress = configuration["AuthServer:Authority"]!.EnsureEndsWith('/') + "connect/logout";
  219. if (previousOnRedirectToIdentityProviderForSignOut != null)
  220. {
  221. await previousOnRedirectToIdentityProviderForSignOut(ctx);
  222. }
  223. };
  224. });
  225. }
  226. context.Services.Configure<AbpClaimsPrincipalFactoryOptions>(options =>
  227. {
  228. options.IsDynamicClaimsEnabled = true;
  229. });
  230. }
  231. private void ConfigureVirtualFileSystem(IWebHostEnvironment hostingEnvironment)
  232. {
  233. if (hostingEnvironment.IsDevelopment())
  234. {
  235. Configure<AbpVirtualFileSystemOptions>(options =>
  236. {
  237. options.FileSets.ReplaceEmbeddedByPhysical<BookStoreDomainSharedModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Acme.BookStore.Domain.Shared"));
  238. options.FileSets.ReplaceEmbeddedByPhysical<BookStoreApplicationContractsModule>(Path.Combine(hostingEnvironment.ContentRootPath, $"..{Path.DirectorySeparatorChar}Acme.BookStore.Application.Contracts"));
  239. options.FileSets.ReplaceEmbeddedByPhysical<BookStoreBlazorModule>(hostingEnvironment.ContentRootPath);
  240. });
  241. }
  242. }
  243. private void ConfigureBlazorise(ServiceConfigurationContext context)
  244. {
  245. context.Services
  246. .AddBootstrap5Providers()
  247. .AddFontAwesomeIcons();
  248. }
  249. private void ConfigureMenu(IConfiguration configuration)
  250. {
  251. Configure<AbpNavigationOptions>(options =>
  252. {
  253. options.MenuContributors.Add(new BookStoreMenuContributor(configuration));
  254. });
  255. Configure<AbpToolbarOptions>(options =>
  256. {
  257. options.Contributors.Add(new BookStoreToolbarContributor());
  258. });
  259. }
  260. private void ConfigureRouter(ServiceConfigurationContext context)
  261. {
  262. Configure<AbpRouterOptions>(options =>
  263. {
  264. options.AppAssembly = typeof(BookStoreBlazorModule).Assembly;
  265. options.AdditionalAssemblies.Add(typeof(BookStoreBlazorClientModule).Assembly);
  266. });
  267. }
  268. private void ConfigureAutoMapper()
  269. {
  270. Configure<AbpAutoMapperOptions>(options =>
  271. {
  272. options.AddMaps<BookStoreBlazorModule>();
  273. });
  274. }
  275. private void ConfigureSwaggerServices(IServiceCollection services)
  276. {
  277. services.AddAbpSwaggerGen(
  278. options =>
  279. {
  280. options.SwaggerDoc("v1", new OpenApiInfo { Title = "BookStore API", Version = "v1" });
  281. options.DocInclusionPredicate((docName, description) => true);
  282. options.CustomSchemaIds(type => type.FullName);
  283. }
  284. );
  285. }
  286. private void ConfigureDataProtection(
  287. ServiceConfigurationContext context,
  288. IConfiguration configuration,
  289. IWebHostEnvironment hostingEnvironment)
  290. {
  291. var dataProtectionBuilder = context.Services.AddDataProtection().SetApplicationName("BookStore");
  292. if (!hostingEnvironment.IsDevelopment())
  293. {
  294. var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
  295. dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, "BookStore-Protection-Keys");
  296. }
  297. }
  298. private void ConfigureDistributedLocking(
  299. ServiceConfigurationContext context,
  300. IConfiguration configuration)
  301. {
  302. context.Services.AddSingleton<IDistributedLockProvider>(sp =>
  303. {
  304. var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
  305. return new RedisDistributedSynchronizationProvider(connection.GetDatabase());
  306. });
  307. }
  308. public override void OnApplicationInitialization(ApplicationInitializationContext context)
  309. {
  310. var env = context.GetEnvironment();
  311. var app = context.GetApplicationBuilder();
  312. if (env.IsDevelopment())
  313. {
  314. app.UseDeveloperExceptionPage();
  315. }
  316. app.UseAbpRequestLocalization();
  317. if (!env.IsDevelopment())
  318. {
  319. app.UseErrorPage();
  320. }
  321. app.UseCorrelationId();
  322. app.UseStaticFiles();
  323. app.UseRouting();
  324. app.UseAuthentication();
  325. if (MultiTenancyConsts.IsEnabled)
  326. {
  327. app.UseMultiTenancy();
  328. }
  329. app.UseDynamicClaims();
  330. app.UseAntiforgery();
  331. app.UseAuthorization();
  332. app.UseSwagger();
  333. app.UseAbpSwaggerUI(options =>
  334. {
  335. options.SwaggerEndpoint("/swagger/v1/swagger.json", "BookStore API");
  336. });
  337. app.UseAbpSerilogEnrichers();
  338. app.UseConfiguredEndpoints(builder =>
  339. {
  340. builder.MapRazorComponents<App>()
  341. .AddInteractiveServerRenderMode()
  342. .AddInteractiveWebAssemblyRenderMode()
  343. .AddAdditionalAssemblies(builder.ServiceProvider.GetRequiredService<IOptions<AbpRouterOptions>>().Value.AdditionalAssemblies.ToArray());
  344. });
  345. }
  346. }