IndexService.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. using IES.ExamServer.Helpers;
  2. using Microsoft.Extensions.Caching.Memory;
  3. using System.Diagnostics;
  4. using System.Net.NetworkInformation;
  5. using System.Net;
  6. using System.Runtime.InteropServices;
  7. using System.Text.Json.Nodes;
  8. using System.Text.RegularExpressions;
  9. using IES.ExamServer.Models;
  10. using System.Text;
  11. using IES.ExamServer.DI;
  12. using IES.ExamServer.Helper;
  13. using System;
  14. using System.Security.Principal;
  15. namespace IES.ExamServer.Services
  16. {
  17. public static class IndexService
  18. {
  19. /// <summary>
  20. /// 修改IP域名映射,以及处理证书是否安装的问题。
  21. /// </summary>
  22. /// <param name="ip"></param>
  23. /// <param name="_memoryCache"></param>
  24. /// <param name="_liteDBFactory"></param>
  25. /// <param name="connectionService"></param>
  26. /// <returns></returns>
  27. public static async Task<(int code, int code_cer ,int code_hosts,int code_zip, string msg)> ModifyHosts(string? ip,IMemoryCache _memoryCache,LiteDBFactory _liteDBFactory,CenterServiceConnectionService connectionService)
  28. {
  29. (string? hostsIp,string hostsMsg) = SystemScriptHelper.FindIpAddressForDomain("exam.habook.local");
  30. int code = 0, code_cer = 0,code_hosts=0,code_zip=0 ;
  31. StringBuilder sb = new StringBuilder();
  32. try
  33. {
  34. string batscriptPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript");
  35. if (!Directory.Exists(batscriptPath))
  36. {
  37. Directory.CreateDirectory(batscriptPath);
  38. }
  39. string pathCerNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript", "certificate.cer");
  40. string pathBatNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript", "install_certificate.bat");
  41. if (!System.IO.File.Exists(pathCerNew) || !System.IO.File.Exists(pathBatNew))
  42. {
  43. string pathCer = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "certificate.cer");
  44. System.IO.File.Copy(pathCer, pathCerNew);
  45. string pathBat = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "install_certificate.bat");
  46. System.IO.File.Copy(pathBat, pathBatNew);
  47. }
  48. var needInstall = SystemScriptHelper.CheckCertificate(pathCerNew);
  49. if (!needInstall)
  50. {
  51. if (SystemScriptHelper.IsAdministrator())
  52. {
  53. var res = ProcessHelper.ExecuteProcess(pathBatNew);
  54. sb.Append(res.msg);
  55. code_cer = res.code;
  56. }
  57. else
  58. {
  59. code_cer = 401;
  60. sb.Append("请使用管理员身份运行本程序,如果已经安装过脚本请忽略!");
  61. }
  62. }
  63. else
  64. {
  65. code_cer = 200;
  66. }
  67. //获取主站配置信息。
  68. ServerDevice serverDevice = _memoryCache.Get<ServerDevice>(Constant._KeyServerDevice);
  69. var primaryNetworks= _liteDBFactory.GetLiteDatabase().GetCollection<Network>().FindAll().ToList();
  70. Network? primaryNetwork = null;
  71. //传入的ip为不为空,切换
  72. if (!string.IsNullOrWhiteSpace(ip) )
  73. {
  74. if (serverDevice != null && serverDevice.networks.IsNotEmpty())
  75. {
  76. primaryNetwork = serverDevice.networks.FindAll(x => ip.Equals(x.ip))?.FirstOrDefault();
  77. }
  78. }
  79. else
  80. {
  81. if (serverDevice != null && serverDevice.networks.IsNotEmpty())
  82. {
  83. //传入的ip为空,则尝试加载 已经配置过的主站域名ip
  84. if (primaryNetworks.IsNotEmpty())
  85. {
  86. foreach (var network in primaryNetworks)
  87. {
  88. var exists = serverDevice.networks.FindAll(x => x.id!.Equals(network.id));
  89. if (exists.IsNotEmpty())
  90. {
  91. if (primaryNetwork == null)
  92. {
  93. primaryNetwork = network;
  94. }
  95. }
  96. }
  97. }
  98. //没有找到主站设置信息,则尝试赋值物理网卡配置信息
  99. if (primaryNetwork == null)
  100. {
  101. primaryNetwork = serverDevice.networks.FirstOrDefault();//第一个是物理网卡
  102. }
  103. }
  104. }
  105. if (primaryNetwork != null)
  106. {
  107. string pathBatHosts = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "modify_hosts.bat");
  108. string text = await System.IO.File.ReadAllTextAsync(pathBatHosts);
  109. // 使用正则表达式替换 IP 地址
  110. string pattern = @"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b";
  111. string result = Regex.Replace(text, pattern, primaryNetwork.ip!);
  112. string pathBatHostsNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript", "modify_hosts.bat");
  113. await System.IO.File.WriteAllTextAsync(pathBatHostsNew, result);
  114. string pathBatStudent = Path.Combine(Directory.GetCurrentDirectory(), "Configs", "cer", "student_manual.bat");
  115. string textStudent = await System.IO.File.ReadAllTextAsync(pathBatStudent);
  116. // 使用正则表达式替换 IP 地址
  117. string resultStudent = Regex.Replace(textStudent, pattern, primaryNetwork.ip!);
  118. string pathBatStudentNew = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "batscript", "student_manual.bat");
  119. await System.IO.File.WriteAllTextAsync(pathBatStudentNew, resultStudent);
  120. if (string.IsNullOrWhiteSpace(hostsIp) || !hostsIp.Equals(primaryNetwork.ip))
  121. {
  122. if (SystemScriptHelper.IsAdministrator())
  123. {
  124. var resHosts = ProcessHelper.ExecuteProcess(pathBatHostsNew);
  125. sb.Append(resHosts.msg);
  126. code_hosts = resHosts.code;
  127. }
  128. else
  129. {
  130. code_hosts = 401;
  131. sb.Append("请使用管理员身份执行本程序!");
  132. }
  133. }
  134. else
  135. {
  136. code_hosts = 200;
  137. sb.Append("IP域名映射已存在,无需再次映射!");
  138. }
  139. string scriptPath= Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "script");
  140. if (!Directory.Exists(scriptPath))
  141. {
  142. Directory.CreateDirectory(scriptPath);
  143. }
  144. string batscriptZipPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "script", "student_script.zip");
  145. var res = ZipHelper.CreateZip(batscriptPath, batscriptZipPath);
  146. if (res.res)
  147. {
  148. code_zip = 200;
  149. sb.Append(res.msg);
  150. }
  151. else
  152. {
  153. code_zip = 400;
  154. sb.Append("脚本文件创建异常!");
  155. }
  156. serverDevice!.networks.ForEach(x =>
  157. {
  158. x.primary = 0;
  159. x.batscriptZip = null;
  160. if (x.id!.Equals(primaryNetwork.id))
  161. {
  162. x.primary = code_hosts ==200? 1:0;
  163. x.batscriptZip = res.res? "script/student_script.zip" : null;
  164. }
  165. });
  166. //更新设备的主站设备信息
  167. connectionService.serverDevice = serverDevice;
  168. _memoryCache.Set<ServerDevice>(Constant._KeyServerDevice, serverDevice);
  169. _liteDBFactory.GetLiteDatabase().GetCollection<ServerDevice>().Upsert(serverDevice);
  170. //清理后再保存,保证只有一条主站数据。
  171. _liteDBFactory.GetLiteDatabase().GetCollection<Network>().DeleteAll();
  172. _liteDBFactory.GetLiteDatabase().GetCollection<Network>().Upsert(primaryNetwork);
  173. //所有执行成功
  174. code = 200;
  175. sb.Append("证书安装成功,域名IP绑定成功,脚本文件创建成功!");
  176. }
  177. }
  178. catch (Exception ex)
  179. {
  180. code = 500;
  181. //_logger.LogError($"域名IP绑定错误。{ex.Message},{ex.StackTrace}");
  182. return (500,code_cer,code_hosts,code_zip, $"域名IP绑定错误,{ex.Message},{ex.StackTrace}");
  183. }
  184. return (code, code_cer, code_hosts, code_zip, sb.ToString());
  185. }
  186. public static async Task<(string content_response, HttpStatusCode code)> GetMusicServer_thirdLocalCacheConfig(IHttpClientFactory httpClientFactory, CenterServiceConnectionService _connectionService , string requestBody)
  187. {
  188. string content_response = string.Empty;
  189. HttpStatusCode code = HttpStatusCode.OK ;
  190. try {
  191. string url = _connectionService!.musicUrl!;
  192. var client = httpClientFactory.CreateClient();
  193. //client.DefaultRequestHeaders.Add("Accept", "application/json, text/plain, */*");
  194. client.DefaultRequestHeaders.Add("appId", Constant._MusicAIServerAppId);
  195. client.DefaultRequestHeaders.Add("encrypt", "1");
  196. client.DefaultRequestHeaders.Add("schoolCode", _connectionService.serverDevice?.school?.id);
  197. var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
  198. // 发送 PUT 请求
  199. HttpResponseMessage response = await client.PutAsync($"{url}/musicLocalCache/thirdLocalCacheConfig", content);
  200. // 处理响应
  201. if (response.IsSuccessStatusCode)
  202. {
  203. content_response = await response.Content.ReadAsStringAsync();
  204. //Console.WriteLine("Response: " + responseData);
  205. }
  206. else
  207. {
  208. // Console.WriteLine("Error: " + response.StatusCode);
  209. code=response.StatusCode;
  210. content_response = await response.Content.ReadAsStringAsync();
  211. }
  212. } catch (Exception ex) {
  213. code= HttpStatusCode.InternalServerError;
  214. content_response = ex.Message;
  215. }
  216. return (content_response, code);
  217. }
  218. public static ServerDevice GetServerDevice( string remote,string region)
  219. {
  220. string hostName = $"{Environment.UserName}-{Dns.GetHostName()}";
  221. string os = RuntimeInformation.OSDescription;
  222. //获取当前客户端的服务端口
  223. string currentUserName = Environment.UserName;
  224. string MachineName =Environment.MachineName;
  225. //var s = Environment;
  226. ServerDevice device = new ServerDevice { name =hostName, userName=currentUserName, os= os,region=region,remote=remote };
  227. int CpuCoreCount = 0;
  228. long MenemorySize = 0;
  229. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  230. {
  231. CpuCoreCount = Environment.ProcessorCount;
  232. MenemorySize = MemoryInfo.GetTotalPhysicalMemory();
  233. //using (PerformanceCounter pc = new PerformanceCounter("Memory", "Available Bytes"))
  234. //{
  235. // // 获取可用内存
  236. // AvailableMemory = (long)pc.NextValue();
  237. //}
  238. //using (PerformanceCounter pc = new PerformanceCounter("Memory", "Committed Bytes"))
  239. //{
  240. // // 获取可用内存
  241. // CommittedMemory= (long)pc.NextValue();
  242. //}
  243. //MenemorySize=AvailableMemory+CommittedMemory;
  244. //
  245. // 获取CPU核心数
  246. //int processorCount = Environment.ProcessorCount;
  247. //Console.WriteLine("CPU 核心数: " + processorCount);
  248. //using (ManagementClass managementClass = new ManagementClass("Win32_Processor"))
  249. //{
  250. // using (ManagementObjectCollection managementObjectCollection = managementClass.GetInstances())
  251. // {
  252. // foreach (ManagementObject managementObject in managementObjectCollection)
  253. // {
  254. // CpuCoreCount += Convert.ToInt32(managementObject.Properties["NumberOfLogicalProcessors"].Value);
  255. // }
  256. // }
  257. //}
  258. //using (ManagementObjectSearcher searcher1 = new ManagementObjectSearcher("SELECT TotalPhysicalMemory FROM Win32_ComputerSystem"))
  259. //{
  260. // foreach (ManagementObject obj in searcher1.Get())
  261. // {
  262. // long MenemorySizes1 = Convert.ToInt64(obj["TotalPhysicalMemory"]);
  263. // break; // 只需要第一个结果
  264. // }
  265. //}
  266. //using (ManagementClass mc = new ManagementClass("Win32_ComputerSystem"))
  267. //{
  268. // using (ManagementObjectCollection moc = mc.GetInstances())
  269. // {
  270. // foreach (ManagementObject mo in moc)
  271. // {
  272. // if (mo["TotalPhysicalMemory"]!= null)
  273. // {
  274. // MenemorySize = Convert.ToInt64(mo["TotalPhysicalMemory"]);
  275. // }
  276. // }
  277. // }
  278. //}
  279. if (Environment.Is64BitOperatingSystem)
  280. {
  281. device.bit="64";
  282. }
  283. else
  284. {
  285. device.bit="32";
  286. }
  287. //ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT Name, MaxClockSpeed FROM Win32_Processor");
  288. //foreach (ManagementObject mo in searcher.Get())
  289. //{
  290. // string? cpuName = mo["Name"].ToString();
  291. // string? clockSpeed = mo["MaxClockSpeed"].ToString();
  292. // //Console.WriteLine($"CPU 名称: {cpuName}");
  293. // //Console.WriteLine($"CPU 主频: {clockSpeed} MHz");
  294. // device.cpuInfos.Add(new CPUInfo { name = cpuName, hz = clockSpeed });
  295. //}
  296. string cpuName = MemoryInfo.GetCpuName();
  297. var clockSpeed = MemoryInfo.GetCpuSpeed();
  298. device.cpuInfos.Add(new CPUInfo { name = cpuName, hz = $"{clockSpeed}" });
  299. }
  300. else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
  301. {
  302. //int processorCount = Environment.ProcessorCount;
  303. // Console.WriteLine("CPU 核心数: " + processorCount);
  304. try {
  305. string cpuInfo = File.ReadAllText("/proc/cpuinfo");
  306. string[] cpu_lines = cpuInfo.Split('\n');
  307. CpuCoreCount= cpu_lines.Count(line => line.StartsWith("processor", StringComparison.OrdinalIgnoreCase));
  308. string? cpuNameLine = cpuInfo.Split('\n').FirstOrDefault(line => line.StartsWith("model name"));
  309. string? clockSpeedLine = cpuInfo.Split('\n').FirstOrDefault(line => line.StartsWith("cpu MHz"));
  310. string cpuName = string.Empty;
  311. string clockSpeed = string.Empty;
  312. if (cpuNameLine!= null)
  313. {
  314. cpuName = cpuNameLine.Split(':').Last().Trim();
  315. }
  316. if (clockSpeedLine!= null)
  317. {
  318. clockSpeed = clockSpeedLine.Split(':').Last().Trim();
  319. }
  320. device.cpuInfos.Add(new CPUInfo { name = cpuName, hz = clockSpeed });
  321. } catch (Exception ex)
  322. {
  323. }
  324. string[] mem_lines = File.ReadAllLines("/proc/meminfo");
  325. var match = mem_lines.FirstOrDefault(line => line.StartsWith("MemTotal:"));
  326. if (match != null)
  327. {
  328. var matchResult = Regex.Match(match, @"\d+");
  329. if (matchResult.Success)
  330. {
  331. MenemorySize= long.Parse(matchResult.Value);
  332. }
  333. }
  334. }
  335. else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
  336. {
  337. try {
  338. using (var process = new Process())
  339. {
  340. process.StartInfo.FileName = "/usr/sbin/sysctl";
  341. process.StartInfo.Arguments = "-n hw.ncpu";
  342. process.StartInfo.RedirectStandardOutput = true;
  343. process.StartInfo.UseShellExecute = false;
  344. process.Start();
  345. string output = process.StandardOutput.ReadToEnd().Trim();
  346. int coreCount;
  347. if (int.TryParse(output, out coreCount))
  348. {
  349. CpuCoreCount= coreCount;
  350. }
  351. }
  352. }
  353. catch (Exception ex) { }
  354. try
  355. {
  356. using (var process = new Process())
  357. {
  358. process.StartInfo.FileName = "/usr/sbin/sysctl";
  359. process.StartInfo.Arguments = "-n hw.memsize";
  360. process.StartInfo.RedirectStandardOutput = true;
  361. process.StartInfo.UseShellExecute = false;
  362. process.Start();
  363. string output = process.StandardOutput.ReadToEnd().Trim();
  364. long memorySize;
  365. if (long.TryParse(output, out memorySize))
  366. {
  367. MenemorySize= memorySize;
  368. }
  369. }
  370. }
  371. catch (Exception ex) { }
  372. try
  373. {
  374. using (var process = new Process())
  375. {
  376. process.StartInfo.FileName = "/usr/sbin/sysctl";
  377. process.StartInfo.Arguments = "-n machdep.cpu.brand_string";
  378. process.StartInfo.RedirectStandardOutput = true;
  379. process.StartInfo.UseShellExecute = false;
  380. process.Start();
  381. string cpuName = process.StandardOutput.ReadToEnd().Trim();
  382. process.StartInfo.FileName = "/usr/sbin/sysctl";
  383. process.StartInfo.Arguments = "-n hw.cpu.frequency";
  384. process.StartInfo.RedirectStandardOutput = true;
  385. process.StartInfo.UseShellExecute = false;
  386. process.Start();
  387. string clockSpeed = process.StandardOutput.ReadToEnd().Trim();
  388. //Console.WriteLine($"CPU 名称: {cpuName}");
  389. //Console.WriteLine($"CPU 主频: {clockSpeed} Hz");
  390. device.cpuInfos.Add(new CPUInfo { name = cpuName, hz = clockSpeed });
  391. }
  392. }
  393. catch (Exception ex)
  394. {
  395. Console.WriteLine($"出现错误: {ex.Message}");
  396. }
  397. if (Environment.Is64BitOperatingSystem)
  398. {
  399. device.bit="64";
  400. }
  401. else
  402. {
  403. device.bit="32";
  404. }
  405. }
  406. if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
  407. {
  408. device.arch="ARM64";
  409. }
  410. else if (RuntimeInformation.ProcessArchitecture == Architecture.Arm)
  411. {
  412. device.arch="ARM32";
  413. }
  414. else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
  415. {
  416. device.arch="X64";
  417. }
  418. else if (RuntimeInformation.ProcessArchitecture == Architecture.X86)
  419. {
  420. device.arch="X86";
  421. }
  422. else
  423. {
  424. device.arch=$"未知({device.arch})";
  425. }
  426. //Console.WriteLine("CPU 核心数: " + CpuCoreCount+",RAM 大小:"+MenemorySize);
  427. device.cpu=CpuCoreCount;
  428. device.ram=MenemorySize;
  429. var nics = NetworkInterface.GetAllNetworkInterfaces();
  430. foreach (var nic in nics)
  431. {
  432. int physical = 0;
  433. if (nic.OperationalStatus == OperationalStatus.Up)
  434. {
  435. if (IsPhysicalNetworkInterface(nic))
  436. {
  437. physical = 1;
  438. }
  439. var name = $"{nic.Name}-{nic.Description}";
  440. var mac = nic.GetPhysicalAddress().ToString();
  441. var properties = nic.GetIPProperties();
  442. var unicastAddresses = properties.UnicastAddresses;
  443. foreach (var unicast in unicastAddresses)
  444. {
  445. if (unicast.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
  446. {
  447. var ip = unicast.Address.ToString();
  448. Network network = new Network() {id=ShaHashHelper.GetSHA1($"{mac}-{name}"), mac=mac, ip=ip, name= name, physical=physical };
  449. if (!string.IsNullOrWhiteSpace(mac.ToString()) && !mac.Equals("000000000000"))
  450. {
  451. device.networks.Add(network);
  452. }
  453. }
  454. }
  455. }
  456. }
  457. //if (_url!.IsNotEmpty())
  458. //{
  459. // List<UriInfo> ports = new List<UriInfo>();
  460. // foreach (var url in _url!)
  461. // {
  462. // Uri uri = new Uri(url);
  463. // device.uris.Add(new UriInfo { port= uri.Port, protocol= uri.Scheme });
  464. // }
  465. //}
  466. //else
  467. //{
  468. // throw new Exception("未获取到端口信息!");
  469. //}
  470. var networks = device.networks.ToList();
  471. if (device.networks.IsNotEmpty())
  472. {
  473. var order= device.networks.OrderByDescending(x => x.physical).ToList();
  474. //for (int i=0; i<order.Count();i++)
  475. //{
  476. // order[i].domain="exam.habook.local";
  477. //}
  478. device.networks=order;
  479. //优先以物理网卡来生成hash,如果没有则以所有网卡生成hash
  480. var physical = order.FindAll(x => x.physical==1);
  481. if (physical.IsNotEmpty())
  482. {
  483. networks=physical;
  484. }
  485. }
  486. StringBuilder sb= new StringBuilder();
  487. sb.Append(device.name);//设备名称
  488. sb.Append(device.os);//系统名称
  489. sb.Append(device.bit);//系统位
  490. sb.Append(device.arch);//指令架构
  491. sb.Append(device.cpu);//cpu核心树
  492. sb.Append(string.Join(",", device.cpuInfos.Select(x=>$"{x.name}{x.hz}")));//cpu名称和频率
  493. sb.Append(device.ram);//内存
  494. sb.Append(string.Join(",", networks.Select(x => $"{x.mac}-{x.name}")));//网卡地址和名称
  495. //暂不使用远程ip和局域网内ip作为hash,可能发生变化
  496. string hashData = ShaHashHelper.GetSHA256(sb.ToString());
  497. device.deviceId=hashData;
  498. device.id= hashData;
  499. return device;
  500. }
  501. public static bool IsPhysicalNetworkInterface(NetworkInterface nic)
  502. {
  503. // 排除虚拟网卡的关键词
  504. string[] virtualKeywords = { "virtual", "hyper-v", "virtualbox", "vmware", "veth","virbr", "tunnel", "docker", "loopback", "vpn","ppp", "slip", "bridge",
  505. "vnic", "vif", "tap", "vlan", "vswitch", "vxlan", "gre", "ipsec", "vrf", "vport", "vnet", "vmac", "vxnet"};
  506. // 检查网卡描述或名称中是否包含虚拟关键词
  507. string description = nic.Description.ToLower();
  508. string name = nic.Name.ToLower();
  509. foreach (var keyword in virtualKeywords)
  510. {
  511. if (description.Contains(keyword,StringComparison.OrdinalIgnoreCase) || name.Contains(keyword, StringComparison.OrdinalIgnoreCase))
  512. {
  513. return false; // 是虚拟网卡
  514. }
  515. }
  516. // 排除一些常见的虚拟网卡类型
  517. if (nic.NetworkInterfaceType == NetworkInterfaceType.Loopback ||
  518. nic.NetworkInterfaceType == NetworkInterfaceType.Tunnel ||
  519. nic.NetworkInterfaceType == NetworkInterfaceType.Ppp ||
  520. nic.NetworkInterfaceType == NetworkInterfaceType.Slip||
  521. nic.NetworkInterfaceType == NetworkInterfaceType.Unknown
  522. )
  523. {
  524. return false; // 是虚拟网卡
  525. }
  526. // 默认认为是物理网卡
  527. return true;
  528. }
  529. /// <summary>
  530. /// 直接获取设备。
  531. /// </summary>
  532. /// <param name="httpContext"></param>
  533. /// <param name="IP"></param>
  534. /// <param name="device_timeSpan"></param>
  535. /// <param name="_azureRedis"></param>
  536. /// <returns></returns>
  537. public static string GetDevice(HttpContext httpContext, IMemoryCache _memoryCache)
  538. {
  539. string IP= GetIP(httpContext);
  540. var cookie = httpContext.Request.Cookies;
  541. string device =string.Empty;
  542. if (cookie != null)
  543. {
  544. ///设备是否存在
  545. foreach (var ck in cookie)
  546. {
  547. if (ck.Key.Equals("device"))
  548. {
  549. //redis如果存在则
  550. var fingerprint = ck.Value.Split("-");
  551. if (fingerprint.Length == 2 && IP.Equals(fingerprint[1]))
  552. {
  553. if (!_memoryCache.TryGetValue<string>($"device:{fingerprint[0]}:{IP}", out device))
  554. {
  555. _memoryCache.Set($"device:{fingerprint[0]}:{IP}", $"{fingerprint[0]}-{IP}");
  556. device = $"{fingerprint[0]}-{IP}";
  557. }
  558. }
  559. }
  560. }
  561. }
  562. return device;
  563. }
  564. public static string GetIP(HttpContext httpContext)
  565. {
  566. var IpPort = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
  567. if (string.IsNullOrEmpty(IpPort))
  568. {
  569. IpPort = $"{httpContext.Connection.RemoteIpAddress}";
  570. }
  571. if (IpPort.Contains("::"))
  572. {
  573. IpPort = "127.0.0.1";
  574. }
  575. return IpPort;
  576. }
  577. /// <summary>
  578. /// 初始化设备
  579. /// </summary>
  580. /// <param name="httpContext"></param>
  581. /// <param name="fingerprint">浏览器指纹</param>
  582. /// <param name="IP"></param>
  583. /// <param name="device_timeSpan"></param>
  584. /// <param name="_azureRedis"></param>
  585. /// <returns></returns>
  586. public static string GetDeviceInit(this HttpContext httpContext, string fingerprint, string IP, IMemoryCache _memoryCache)
  587. {
  588. string device = $"{fingerprint}-{IP}";
  589. List<string> cookieString = new List<string>();
  590. var cookie = httpContext.Request.Cookies;
  591. int status = 1;
  592. if (cookie != null)
  593. {
  594. ///设备是否存在
  595. foreach (var ck in cookie)
  596. {
  597. if (ck.Key.Equals("device"))
  598. {
  599. if (device.Contains("-") && device.Contains("."))
  600. {
  601. //如果匹配的是fingerprint-IP 则是已经存在的。
  602. if (ck.Value.Equals(device))
  603. {
  604. //redis如果存在则
  605. _memoryCache.TryGetValue<string>($"device:{fingerprint}:{IP}", out string device_exist);
  606. // 返回的则应该是ck.Value=exist_device_exist的数据
  607. if (device_exist!=null)
  608. {
  609. if (!string.IsNullOrWhiteSpace($"{device_exist}"))
  610. {
  611. //0是代表指纹和IP匹配,正常返回的
  612. status = 1;
  613. }
  614. else
  615. {
  616. //需要新建 fingerprint-IP
  617. status = 1;
  618. }
  619. }
  620. else
  621. {
  622. status = 1;
  623. }
  624. }
  625. else
  626. {
  627. string ck_ip = ck.Value.Split("-")[1];
  628. if (ck_ip.Equals(IP))
  629. {
  630. //传入的指纹和cookie的不一致,仍然以cookie的为准。
  631. status = 1;
  632. fingerprint = ck.Value.Split("-").First();
  633. device = ck.Value;
  634. }
  635. }
  636. }
  637. else
  638. {
  639. //如果匹配的是fingerprint则是一个新的设备。
  640. if (ck.Value.Equals(fingerprint))
  641. {
  642. //检查设备是否被占用
  643. //var device_exist = _azureRedis.GetRedisClient(8).HashExists($"device:{fingerprint}", IP);
  644. _memoryCache.TryGetValue<JsonNode>($"device:{fingerprint}:{IP}", out JsonNode device_exist);
  645. if (device_exist!=null)
  646. {
  647. //需要新建 sha1(fingerprint+uuid)-IP
  648. status = 2;
  649. }
  650. else
  651. {
  652. //0是代表指纹和IP匹配,正常返回的
  653. status = 1;
  654. }
  655. }
  656. else
  657. {
  658. //匹配的都不是,新设备。
  659. status = 1;
  660. }
  661. }
  662. }
  663. else
  664. {
  665. cookieString.Add($"{ck.Key}{ck.Value}");
  666. }
  667. }
  668. }
  669. /*
  670. httpContext.Request.Headers.TryGetValue("accept-language", out var accept_language);
  671. httpContext.Request.Headers.TryGetValue("sec-ch-ua", out var chua);
  672. httpContext.Request.Headers.TryGetValue("sec-ch-ua-platform", out var platform);
  673. httpContext.Request.Headers.TryGetValue("user-agent", out var useragent);
  674. httpContext.Request.Headers.TryGetValue("accept", out var accept);
  675. httpContext.Request.Headers.TryGetValue("accept-encoding", out var accept_encoding);
  676. device = ShaHashHelper.GetSHA1($"{IP}{accept_language}{chua}{platform}{useragent}{accept}{accept_encoding}{string.Join("", cookieString)}");
  677. */
  678. if (status == 2)
  679. {
  680. fingerprint = ShaHashHelper.GetSHA1(fingerprint + Guid.NewGuid().ToString());
  681. device = $"{fingerprint}-{IP}";
  682. }
  683. //else if (status == 1)
  684. //{
  685. // device = $"{fingerprint}-{IP}";
  686. //}
  687. //await _azureRedis.GetRedisClient(8).HashSetAsync($"device:{fingerprint}", IP, new { device }.ToJsonString());
  688. //await _azureRedis.GetRedisClient(8).KeyExpireAsync($"device:{fingerprint}", device_timeSpan);
  689. _memoryCache.Set($"device:{fingerprint}:{IP}", device);
  690. httpContext.Response.Cookies.Append("device", device, new CookieOptions { HttpOnly = true, MaxAge = new TimeSpan(24 * 7, 0, 0) });
  691. return device;
  692. }
  693. }
  694. public class UriInfo
  695. {
  696. public string? protocol { get; set; }
  697. public int port { get; set; }
  698. }
  699. }