Program.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. using Hangfire;
  2. using Hangfire.Redis.StackExchange;
  3. using Microsoft.AspNetCore.Authentication.JwtBearer;
  4. using Microsoft.Extensions.DependencyInjection.Extensions;
  5. using Microsoft.IdentityModel.Tokens;
  6. using System.IdentityModel.Tokens.Jwt;
  7. using TEAMModelOS.SDK.DI;
  8. using TEAMModelOS.SDK;
  9. using HTEX.Complex.Services;
  10. using HTEX.Complex.Services.MQTT;
  11. using MathNet.Numerics;
  12. using MQTTnet.AspNetCore;
  13. using MQTTnet.Server;
  14. using Microsoft.Extensions.Options;
  15. using System.Threading;
  16. using Microsoft.Extensions.Logging;
  17. using System.Text.Json;
  18. using Microsoft.Extensions.Hosting;
  19. using MQTTnet.AspNetCore.Routing;
  20. using Microsoft.AspNetCore.Builder;
  21. namespace HTEX.Complex
  22. {
  23. public class Program
  24. {
  25. public static void Main(string[] args)
  26. {
  27. var builder = WebApplication.CreateBuilder(args); //builder.WebHost.ConfigureKestrel(options =>
  28. //{
  29. // //options.ListenAnyIP(4001, options => {
  30. // // // options.UseHttps("Crt/iteden.pfx", "iteden");
  31. // //});
  32. // options.ListenAnyIP(1883, options => { options.UseMqtt();/*options.UseHttps("Crt/iteden.pfx", "iteden");*/ });
  33. // options.ListenAnyIP(1884, options => { options.UseMqtt();/* options.UseHttps("Configs/Crt/iteden.pfx", "iteden"); */}); // Default HTTP pipeline
  34. //});
  35. //builder.WebHost.ConfigureKestrel(options =>
  36. //{
  37. // //options.ListenAnyIP(4001, options => {
  38. // // // options.UseHttps("Crt/iteden.pfx", "iteden");
  39. // //});
  40. // options.ListenAnyIP(1883, options => { options.UseMqtt();/*options.UseHttps("Crt/iteden.pfx", "iteden");*/ });
  41. // options.ListenAnyIP(1884, options => { options.UseMqtt();/* options.UseHttps("Configs/Crt/iteden.pfx", "iteden"); */}); // Default HTTP pipeline
  42. //});
  43. // Add services to the container.
  44. JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
  45. builder.Services.AddAuthentication(options => options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
  46. .AddJwtBearer(options => //AzureADJwtBearer
  47. {
  48. //options.SaveToken = true; //驗證令牌由服務器生成才有效,不適用於服務重啟或分布式架構
  49. options.Authority ="https://login.chinacloudapi.cn/4807e9cf-87b8-4174-aa5b-e76497d7392b/v2.0";// builder.Configuration["Option:Authority"];
  50. options.Audience = "72643704-b2e7-4b26-b881-bd5865e7a7a5";//builder.Configuration["Option:Audience"];
  51. options.RequireHttpsMetadata = true;
  52. options.TokenValidationParameters = new TokenValidationParameters
  53. {
  54. RoleClaimType = "roles",
  55. //ValidAudiences = new string[] { builder.Configuration["Option:Audience"], $"api://{builder.Configuration["Option:Audience"]}" }
  56. ValidAudiences = new string[] { "72643704-b2e7-4b26-b881-bd5865e7a7a5", $"api://72643704-b2e7-4b26-b881-bd5865e7a7a5" }
  57. };
  58. options.Events = new JwtBearerEvents();
  59. //下列事件有需要紀錄則打開
  60. //options.Events.OnMessageReceived = async context => { await Task.FromResult(0); };
  61. //options.Events.OnForbidden = async context => { await Task.FromResult(0); };
  62. //options.Events.OnChallenge = async context => { await Task.FromResult(0); };
  63. //options.Events.OnAuthenticationFailed = async context => { await Task.FromResult(0); };
  64. options.Events.OnTokenValidated = async context =>
  65. {
  66. if (!context.Principal.Claims.Any(x => x.Type.Equals("http://schemas.microsoft.com/identity/claims/scope")) //ClaimConstants.Scope
  67. && !context.Principal.Claims.Any(y => y.Type.Equals("roles"))) //ClaimConstants.Roles //http://schemas.microsoft.com/ws/2008/06/identity/claims/role
  68. {
  69. //TODO 需處理額外授權非角色及範圍的訪問異常紀錄
  70. throw new UnauthorizedAccessException("Neither scope or roles claim was found in the bearer token.");
  71. }
  72. await Task.FromResult(0);
  73. };
  74. });
  75. builder.Services.AddControllers();
  76. #if DEBUG
  77. builder.WebHost.UseUrls(new[] { "https://*:7298" });
  78. #endif
  79. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
  80. builder.Services.AddEndpointsApiExplorer();
  81. //builder.Services.AddSwaggerGen();
  82. builder.Services.AddHttpClient();
  83. string? StorageConnectionString = builder.Configuration.GetValue<string>("Azure:Storage:ConnectionString");
  84. string? RedisConnectionString = builder.Configuration.GetValue<string>("Azure:Redis:ConnectionString");
  85. //Storage
  86. builder.Services.AddAzureStorage(StorageConnectionString, "Default");
  87. //Redis
  88. builder.Services.AddAzureRedis(RedisConnectionString, "Default");
  89. string? StorageConnectionStringTest = builder.Configuration.GetValue<string>("Azure:Storage:ConnectionString-Test");
  90. //Storage
  91. builder.Services.AddAzureStorage(StorageConnectionString, "Test");
  92. builder.Services.AddSignalR();
  93. builder.Services.AddHttpContextAccessor();
  94. builder.Services.AddHttpClient<DingDing>();
  95. string path = $"{builder.Environment.ContentRootPath}/JsonFiles";
  96. builder.Services.TryAddSingleton(new Region2LongitudeLatitudeTranslator(path));
  97. builder.Services.AddIPSearcher(path);
  98. builder.Services.AddCors(options =>
  99. {
  100. options.AddDefaultPolicy(
  101. builder =>
  102. {
  103. builder.AllowAnyOrigin()
  104. .AllowAnyHeader()
  105. .AllowAnyMethod();
  106. });
  107. });
  108. #if !DEBUG
  109. builder.Services.AddHangfire(config => {
  110. config.UseRedisStorage(builder.Configuration.GetValue<string>("Azure:Redis:ConnectionString"));
  111. });
  112. builder.Services.AddHangfireServer();
  113. #endif
  114. builder.Services.AddControllersWithViews();
  115. //MQTT 服务端API 发送消息到MQTT客户端 https://www.cnblogs.com/weskynet/p/16441219.html
  116. // builder.Services.AddHostedService<MqttHostService>();
  117. #region MQTT配置
  118. //string hostIp = Configuration["MqttOption:HostIp"];//IP地址
  119. //int hostPort = int.Parse(Configuration["MqttOption:HostPort"]);//端口号
  120. //int timeout = int.Parse(Configuration["MqttOption:Timeout"]);//超时时间
  121. //string username = Configuration["MqttOption:UserName"];//用户名
  122. //string password = Configuration["MqttOption:Password"];//密码
  123. builder.Services.AddSingleton<MQTTEvents>();
  124. builder.Services.AddSingleton(new JsonSerializerOptions(JsonSerializerDefaults.Web));
  125. builder.Services.AddHostedMqttServerWithServices(x => {
  126. x.WithDefaultEndpoint()
  127. //.WithDefaultEndpointBoundIPAddress(System.Net.IPAddress.Parse("127.0.0.1"))
  128. //.WithDefaultEndpointPort(1883)
  129. //.WithEncryptedEndpointPort(1884)
  130. .WithConnectionBacklog(1000)
  131. .WithPersistentSessions(true).WithKeepAlive()
  132. .WithDefaultCommunicationTimeout(TimeSpan.FromMilliseconds(30));
  133. }).AddMqttConnectionHandler().AddConnections().AddMqttControllers();
  134. #endregion
  135. var app = builder.Build();
  136. var events = app.Services.GetRequiredService<MQTTEvents>();
  137. // Configure the HTTP request pipeline.
  138. if (!app.Environment.IsDevelopment())
  139. {
  140. app.UseExceptionHandler("/Home/Error");
  141. // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
  142. app.UseHsts();
  143. }
  144. app.UseHttpsRedirection();
  145. app.UseStaticFiles();
  146. app.UseRouting();
  147. app.UseCors(); //使用跨域設定
  148. app.UseHttpsRedirection(); //開發中暫時關掉
  149. app.UseAuthentication();
  150. app.UseAuthorization();
  151. //app.MapControllerRoute(
  152. // name: "default",
  153. // pattern: "{controller=Home}/{action=Index}/{id?}");
  154. //app.UseEndpoints(endpoints => {
  155. // endpoints.MapControllers();
  156. // endpoints.MapConnectionHandler<MqttConnectionHandler>("/mqtt", opts => opts.WebSockets.SubProtocolSelector = protocolList => protocolList.FirstOrDefault() ?? string.Empty);
  157. // endpoints.MapFallbackToFile("index.html");
  158. // endpoints.MapHub<SignalRScreenServerHub>("/signalr/screen").RequireCors("any");
  159. //});
  160. app.MapControllers();
  161. app.MapConnectionHandler<MqttConnectionHandler>("/mqtt", opts => opts.WebSockets.SubProtocolSelector = protocolList => protocolList.FirstOrDefault() ?? string.Empty);
  162. app.MapFallbackToFile("index.html");
  163. app.MapHub<SignalRScreenServerHub>("/signalr/screen").RequireCors("any");
  164. app.UseMqttServer(server =>
  165. {
  166. server.WithAttributeRouting(app.Services, allowUnmatchedRoutes: false);
  167. server.ClientSubscribedTopicAsync+=events._mqttServer_ClientSubscribedTopicAsync;// 客户端订阅主题事件
  168. server.StoppedAsync+=events._mqttServer_StoppedAsync;// 关闭后事件
  169. server.ValidatingConnectionAsync+=events._mqttServer_ValidatingConnectionAsync; // 用户名和密码验证有关
  170. server.InterceptingPublishAsync+=events._mqttServer_InterceptingPublishAsync;// 消息接收事件
  171. server.StartedAsync+=events._mqttServer_StartedAsync;// 启动后事件
  172. server.ClientUnsubscribedTopicAsync+=events._mqttServer_ClientUnsubscribedTopicAsync;// 客户端取消订阅事件
  173. server.ApplicationMessageNotConsumedAsync+=events._mqttServer_ApplicationMessageNotConsumedAsync; // 消息接收事件,应用程序消息未使用
  174. server.ClientDisconnectedAsync+=events._mqttServer_ClientDisconnectedAsync;// 客户端关闭事件
  175. server.ClientConnectedAsync+=events._mqttServer_ClientConnectedAsync;//客户端连接事件
  176. //server.InterceptingClientEnqueueAsync += events._mqttServer_InterceptingClientEnqueueAsync;//拦截客户端排队
  177. //server.ClientAcknowledgedPublishPacketAsync += events._mqttServer_ClientAcknowledgedPublishPacketAsync;//已确认发布数据包
  178. });
  179. app.Run();
  180. }
  181. }
  182. }