StartupHelper.cs 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. using System.IdentityModel.Tokens.Jwt;
  2. using System.Reflection;
  3. using System.Text;
  4. using Hotline.Application.Orders;
  5. using Hotline.Identity;
  6. using Hotline.Repository.SqlSugar;
  7. using Hotline.Repository.SqlSugar.Ts;
  8. using Mapster;
  9. using MapsterMapper;
  10. using Microsoft.AspNetCore.Authentication.JwtBearer;
  11. using Microsoft.IdentityModel.Tokens;
  12. using Microsoft.OpenApi.Models;
  13. using XF.Domain.Cache;
  14. using XF.Domain.Entities;
  15. using XF.Domain.Exceptions;
  16. using XF.Domain.Options;
  17. using XF.Domain.Repository;
  18. namespace Hotline.Api
  19. {
  20. public static class StartupHelper
  21. {
  22. /// <summary>
  23. /// Authentication
  24. /// </summary>
  25. /// <param name="services"></param>
  26. /// <param name="configuration"></param>
  27. /// <returns></returns>
  28. public static IServiceCollection RegisterAuthentication(this IServiceCollection services, ConfigurationManager configuration)
  29. {
  30. var jwtOptions = configuration.GetSection("IdentityConfiguration").Get<IdentityConfiguration>().Jwt;
  31. #region remote ids
  32. //JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
  33. //services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  34. // .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, d =>
  35. // {
  36. // d.Authority = identityConfigs.IdentityUrl;
  37. // d.RequireHttpsMetadata = false;
  38. // d.TokenValidationParameters = new TokenValidationParameters
  39. // {
  40. // ValidateAudience = false
  41. // };
  42. // //d.Audience = "hotline_api";
  43. // d.Events = new JwtBearerEvents
  44. // {
  45. // OnMessageReceived = context =>
  46. // {
  47. // var accessToken = context.Request.Query["access_token"];
  48. // // If the request is for our hub...
  49. // var path = context.HttpContext.Request.Path;
  50. // if (!string.IsNullOrEmpty(accessToken) &&
  51. // (path.StartsWithSegments("/hubs/callcenter")))
  52. // {
  53. // // Read the token out of the query string
  54. // context.Token = accessToken;
  55. // }
  56. // return Task.CompletedTask;
  57. // }
  58. // };
  59. // });
  60. #endregion
  61. services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  62. .AddJwtBearer(d =>
  63. {
  64. byte[] bytes = Encoding.UTF8.GetBytes(jwtOptions.SecretKey);
  65. var secKey = new SymmetricSecurityKey(bytes);
  66. d.TokenValidationParameters = new()
  67. {
  68. ValidateIssuer = false,
  69. ValidateAudience = true,
  70. ValidateLifetime = true,
  71. ValidateIssuerSigningKey = true,
  72. IssuerSigningKey = secKey,
  73. AudienceValidator = (audiences, token, parameters) =>
  74. {
  75. if (token is JwtSecurityToken jwtToken)
  76. {
  77. using var serviceProvider = services.BuildServiceProvider();
  78. var cacheAudience = serviceProvider.GetService<ITypedCache<AudienceTicket>>();
  79. var audience = cacheAudience.Get(jwtToken.Subject);
  80. return audiences != null && audiences.Any(a => a == audience?.Ticket);
  81. }
  82. return false;
  83. }
  84. };
  85. //d.Audience = "hotline_api";
  86. d.Events = new JwtBearerEvents
  87. {
  88. OnMessageReceived = context =>
  89. {
  90. var accessToken = context.Request.Query["access_token"];
  91. // If the request is for our hub...
  92. var path = context.HttpContext.Request.Path;
  93. if (!string.IsNullOrEmpty(accessToken) &&
  94. (path.StartsWithSegments("/hubs/hotline")))
  95. {
  96. // Read the token out of the query string
  97. context.Token = accessToken;
  98. }
  99. return Task.CompletedTask;
  100. }
  101. };
  102. })
  103. ;
  104. return services;
  105. }
  106. /// <summary>
  107. /// Swagger
  108. /// </summary>
  109. /// <param name="services"></param>
  110. /// <returns></returns>
  111. public static IServiceCollection RegisterSwagger(this IServiceCollection services)
  112. {
  113. services.AddSwaggerGen(c =>
  114. {
  115. //添加文档
  116. c.SwaggerDoc("v1", new OpenApiInfo() { Title = "Hotline Api", Version = "v1.0", Description = "智慧热线api" });
  117. var files = Directory.GetFiles(AppContext.BaseDirectory).Where(d => d.EndsWith(".xml"));
  118. foreach (var file in files)
  119. {
  120. c.IncludeXmlComments(file, true);
  121. }
  122. var scheme = new OpenApiSecurityScheme()
  123. {
  124. Description = "Authorization header. \r\nExample: 'Bearer ***'",
  125. Reference = new OpenApiReference
  126. {
  127. Type = ReferenceType.SecurityScheme,
  128. Id = "Authorization"
  129. },
  130. Scheme = "oauth2",
  131. Name = "Authorization",
  132. In = ParameterLocation.Header,
  133. Type = SecuritySchemeType.ApiKey,
  134. };
  135. c.AddSecurityDefinition("Authorization", scheme);
  136. var requirement = new OpenApiSecurityRequirement();
  137. requirement[scheme] = new List<string>();
  138. c.AddSecurityRequirement(requirement);
  139. });
  140. return services;
  141. }
  142. /// <summary>
  143. /// Cors
  144. /// </summary>
  145. /// <param name="services"></param>
  146. /// <param name="configuration"></param>
  147. /// <param name="corsOrigins"></param>
  148. /// <returns></returns>
  149. public static IServiceCollection RegisterCors(this IServiceCollection services, ConfigurationManager configuration, string corsOrigins)
  150. {
  151. services.AddCors(options =>
  152. {
  153. options.AddPolicy(name: corsOrigins,
  154. builder =>
  155. {
  156. var origins = configuration.GetSection("Cors:Origins").Get<string[]>();
  157. builder.SetIsOriginAllowed(a =>
  158. {
  159. return origins.Any(origin => origin.StartsWith("*.", StringComparison.Ordinal)
  160. ? a.EndsWith(origin[1..], StringComparison.Ordinal)
  161. : a.Equals(origin, StringComparison.Ordinal));
  162. })
  163. .AllowAnyHeader()
  164. .AllowAnyMethod()
  165. .AllowCredentials();
  166. });
  167. });
  168. return services;
  169. }
  170. /// <summary>
  171. /// Mapper
  172. /// </summary>
  173. /// <param name="services"></param>
  174. /// <returns></returns>
  175. public static IServiceCollection RegisterMapper(this IServiceCollection services)
  176. {
  177. var config = TypeAdapterConfig.GlobalSettings;
  178. config.ForDestinationType<IDataPermission>()
  179. .Ignore(d => d.CreatorId)
  180. .Ignore(d => d.CreatorOrgId)
  181. //.Ignore(d => d.CreatorOrgCode)
  182. .Ignore(d => d.AreaId);
  183. config.ForDestinationType<IWorkflow>()
  184. .Ignore(d => d.ExpiredTimeConfigId);
  185. config.ForDestinationType<IHasCreationTime>()
  186. .Ignore(d => d.CreationTime);
  187. config.ForDestinationType<IHasDeletionTime>().Ignore(d => d.DeletionTime);
  188. config.ForDestinationType<ISoftDelete>().Ignore(d => d.IsDeleted);
  189. config.ForDestinationType<IHasModificationTime>().Ignore(d => d.LastModificationTime);
  190. config.ForDestinationType<Entity>().Ignore(d => d.Id);
  191. services.AddSingleton(config);
  192. services.AddScoped<IMapper, ServiceMapper>();
  193. return services;
  194. }
  195. /// <summary>
  196. /// SignalR
  197. /// </summary>
  198. /// <param name="services"></param>
  199. /// <param name="configuration"></param>
  200. /// <returns></returns>
  201. public static IServiceCollection RegisterSignalR(this IServiceCollection services, ConfigurationManager configuration)
  202. {
  203. var connectionString = configuration.GetConnectionString("Redis");
  204. if (string.IsNullOrEmpty(connectionString))
  205. throw new UserFriendlyException("未配置signalR的redis连接");
  206. services.AddSignalR().AddStackExchangeRedis(connectionString, options =>
  207. {
  208. options.Configuration.ChannelPrefix = "Hotline:signalr:";
  209. });
  210. return services;
  211. }
  212. public static IServiceCollection RegisterRepository(this IServiceCollection services)
  213. {
  214. services.AddScoped(typeof(IRepository<>), typeof(BaseRepository<>));
  215. services.AddScoped(typeof(IRepositoryWorkflow<>), typeof(BaseRepositoryWorkflow<>));
  216. services.AddScoped(typeof(IRepositoryTextSearch<>), typeof(BaseRepositoryTextSearch<>));
  217. return services;
  218. }
  219. }
  220. }