LoginService.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. using Azure.Cosmos;
  2. using Microsoft.AspNetCore.Http;
  3. using Microsoft.Extensions.Logging;
  4. using StackExchange.Redis;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. using TEAMModelOS.Models;
  11. using TEAMModelOS.SDK.DI;
  12. using TEAMModelOS.SDK.Models.Table;
  13. using static TEAMModelOS.SDK.Models.Teacher;
  14. namespace TEAMModelOS.SDK.Models.Service
  15. {
  16. public static class LoginService
  17. {
  18. /// <summary>
  19. /// //添加用户登录信息和在线登录
  20. /// </summary>
  21. /// <param name="school">学校</param>
  22. /// <param name="scope">登录类型Teacher Student TmdUser</param>
  23. /// <param name="id">登录者的ID</param>
  24. /// <param name="ip">登陆者的IP地址</param>
  25. /// <param name="_azureRedis">redis</param>
  26. /// <param name="_azureStorage">table表</param>
  27. /// <param name="client">cosmosDB数据库连接</param>
  28. /// <param name="expire">到期时间</param>
  29. /// <param name="region">上次登录地址</param>
  30. /// <returns></returns>
  31. public static async Task<List<LoginInfo>> DoLoginInfo(List<LoginInfo> loginInfos, string school, string scope, string id, string ip, AzureRedisFactory _azureRedis, AzureStorageFactory _azureStorage, int expire = 1, string region = null)
  32. {
  33. var table = _azureStorage.GetCloudTableClient().GetTableReference("IESLogin");
  34. DateTimeOffset dateTime = DateTimeOffset.UtcNow;
  35. var dateHour = dateTime.ToString("yyyyMMddHH"); //获取当天的小时
  36. var dateDay = dateTime.ToString("yyyyMMdd"); //获取当天的日期
  37. var dateMonth = dateTime.ToString("yyyyMM");//获取当月的日期
  38. var currentHour = dateTime.Hour;
  39. var currentDay = dateTime.Day;
  40. long Expire = dateTime.AddHours(expire).ToUnixTimeMilliseconds(); //token到期时间
  41. long now = dateTime.ToUnixTimeMilliseconds(); //时间戳
  42. DateTime hour = DateTime.UtcNow.AddHours(25); //25小时到期
  43. DateTime month = DateTime.UtcNow.AddDays(32); //一个月到期
  44. if (loginInfos.Any())
  45. {
  46. if (loginInfos.Count() >= 5)
  47. {
  48. loginInfos = loginInfos.OrderBy(x => x.expire).ToList();
  49. loginInfos.RemoveRange(4, loginInfos.Count() - 4);
  50. }
  51. loginInfos.Add(new LoginInfo { expire = Expire, ip = ip, time = now });
  52. }
  53. else
  54. loginInfos = new List<LoginInfo> { new LoginInfo { expire = Expire, ip = ip, time = now } };
  55. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:IES:{scope}:{dateDay}", $"{currentHour}", 1);//一天24小时
  56. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:IES:{scope}:{dateMonth}", $"{currentDay}", 1); //当天的累计
  57. var resDay = await _azureRedis.GetRedisClient(8).KeyTimeToLiveAsync($"Login:IES:{scope}:{dateDay}");
  58. if (resDay == null)
  59. {
  60. await _azureRedis.GetRedisClient(8).KeyExpireAsync($"Login:IES:{scope}:{dateDay}", hour); //设置到期时间
  61. }
  62. var rspMonth = await _azureRedis.GetRedisClient(8).KeyTimeToLiveAsync($"Login:IES:{scope}:{dateMonth}");
  63. if (rspMonth == null)
  64. {
  65. await _azureRedis.GetRedisClient(8).KeyExpireAsync($"Login:IES:{scope}:{dateMonth}", month); //设置到期时间
  66. }
  67. ////查询Redis是否有值
  68. //var dayCnt = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:IES:{scope}:{dateDay}");
  69. //List<dynamic> dayCounts = new();
  70. //if (dayCnt != null && dayCnt.Length > 0)
  71. //{
  72. // foreach (var hourCnt in dayCnt)
  73. // {
  74. // dayCounts.Add(new { code = hourCnt.Element.ToString(), count = (int)hourCnt.Score });
  75. // }
  76. //}
  77. //var monthCnt = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:IES:{scope}:{dateMonth}");
  78. //List<dynamic> monthCounts = new();
  79. //if (monthCnt != null && monthCnt.Length > 0)
  80. //{
  81. // foreach (var mCnt in monthCnt)
  82. // {
  83. // monthCounts.Add(new { code = mCnt.Element.ToString(), count = (int)mCnt.Score });
  84. // }
  85. //}
  86. //保存当天每小时的峰值
  87. List<HourLogin> hourLogins = await table.QueryWhereString<HourLogin>($"PartitionKey eq 'HourLogin' and RowKey eq '{dateHour}'");
  88. if (hourLogins.Count > 0)
  89. {
  90. foreach (var hourLogin in hourLogins)
  91. {
  92. //hourLogin.Hour = currentHour;
  93. if (scope.Equals("teacher"))
  94. hourLogin.Teacher += 1;
  95. else if (scope.Equals("student"))
  96. hourLogin.Student += 1;
  97. else
  98. hourLogin.TmdUser += 1;
  99. }
  100. try
  101. {
  102. await table.SaveOrUpdateAll(hourLogins);
  103. }
  104. catch
  105. {
  106. }
  107. }
  108. else
  109. {
  110. HourLogin hourLogin = new() { PartitionKey = $"HourLogin", RowKey = dateHour, Hour = currentHour };
  111. if (scope.Equals("teacher"))
  112. {
  113. hourLogin.Teacher = 1;
  114. hourLogin.Student = 0;
  115. hourLogin.TmdUser = 0;
  116. }
  117. else if (scope.Equals("student"))
  118. {
  119. hourLogin.Teacher = 0;
  120. hourLogin.Student = 1;
  121. hourLogin.TmdUser = 0;
  122. }
  123. else
  124. {
  125. hourLogin.Teacher = 0;
  126. hourLogin.Student = 0;
  127. hourLogin.TmdUser = 1;
  128. }
  129. try
  130. {
  131. await table.SaveOrUpdate<HourLogin>(hourLogin);//保存在线数据
  132. }
  133. catch
  134. {
  135. }
  136. }
  137. //保存当天的峰值
  138. List<DayLogin> dayLogins = await table.QueryWhereString<DayLogin>($"PartitionKey eq 'DayLogin' and RowKey eq '{dateDay}'");
  139. if (dayLogins.Count > 0)
  140. {
  141. foreach (var dayLogin in dayLogins)
  142. {
  143. //dayLogin.Day = currentDay;
  144. if (scope.Equals("teacher"))
  145. dayLogin.Teacher += 1;
  146. else if (scope.Equals("student"))
  147. dayLogin.Student += 1;
  148. else
  149. dayLogin.TmdUser += 1;
  150. }
  151. try
  152. {
  153. await table.SaveOrUpdateAll(dayLogins);
  154. }
  155. catch
  156. {
  157. }
  158. }
  159. else
  160. {
  161. //保存当月每天的峰值
  162. DayLogin dayLogin = new() { PartitionKey = $"DayLogin", RowKey = dateDay, Day = currentDay };
  163. if (scope.Equals("teacher"))
  164. {
  165. dayLogin.Teacher = 1;
  166. dayLogin.Student = 0;
  167. dayLogin.TmdUser = 0;
  168. }
  169. else if (scope.Equals("student"))
  170. {
  171. dayLogin.Teacher = 0;
  172. dayLogin.Student = 1;
  173. dayLogin.TmdUser = 0;
  174. }
  175. else
  176. {
  177. dayLogin.Teacher = 0;
  178. dayLogin.Student = 0;
  179. dayLogin.TmdUser = 1;
  180. }
  181. await table.SaveOrUpdate<DayLogin>(dayLogin);//保存在线数据
  182. }
  183. if (!string.IsNullOrWhiteSpace(school))
  184. {
  185. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:School:{school}:{scope}:{dateDay}", $"{currentHour}", 1);//当天当前小时在线人加1
  186. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Login:School:{school}:{scope}:{dateMonth}", $"{currentDay}", 1); //当天的在线加1
  187. var reScDay = await _azureRedis.GetRedisClient(8).KeyTimeToLiveAsync($"Login:School:{school}:{scope}:{dateDay}");
  188. if (reScDay == null)
  189. {
  190. await _azureRedis.GetRedisClient(8).KeyExpireAsync($"Login:School:{school}:{scope}:{dateDay}", hour); //设置到期时间
  191. }
  192. var reScMonth = await _azureRedis.GetRedisClient(8).KeyTimeToLiveAsync($"Login:School:{school}:{scope}:{dateMonth}");
  193. if (reScMonth == null)
  194. {
  195. await _azureRedis.GetRedisClient(8).KeyExpireAsync($"Login:School:{school}:{scope}:{dateMonth}", month); //设置到期时间
  196. }
  197. ////查询Redis是否有值
  198. //var scDayCnt = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:School:{school}:{scope}:{dateDay}");
  199. //List<dynamic> scDayCounts = new();
  200. //if (scDayCnt != null && scDayCnt.Length > 0)
  201. //{
  202. // foreach (var itemHour in scDayCnt)
  203. // {
  204. // scDayCounts.Add(new { code = itemHour.Element.ToString(), count = (int)itemHour.Score });
  205. // }
  206. //}
  207. //var ScMonth = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Login:School:{school}:{scope}:{dateMonth}");
  208. //List<dynamic> scMonthCount = new();
  209. //if (ScMonth != null && ScMonth.Length > 0)
  210. //{
  211. // foreach (var count in ScMonth)
  212. // {
  213. // scMonthCount.Add(new { code = count.Element.ToString(), count = (int)count.Score });
  214. // }
  215. //}
  216. //保存学校当天每小时的
  217. List<HourLoginSchool> hourLoginSchools = await table.QueryWhereString<HourLoginSchool>($"PartitionKey eq 'HourLogin-{school}' and RowKey eq '{dateHour}'");
  218. if (hourLoginSchools.Count > 0)
  219. {
  220. foreach (var hLoginSc in hourLoginSchools)
  221. {
  222. //hLoginSc.Hour = currentHour;
  223. if (scope.Equals("teacher"))
  224. hLoginSc.Teacher += 1;
  225. else if (scope.Equals("student"))
  226. hLoginSc.Student += 1;
  227. else
  228. hLoginSc.TmdUser += 1;
  229. }
  230. try
  231. {
  232. await table.SaveOrUpdateAll(hourLoginSchools);
  233. }
  234. catch
  235. {
  236. }
  237. }
  238. else
  239. {
  240. //学校小时峰值
  241. HourLoginSchool hourLoginSc = new() { PartitionKey = $"HourLogin-{school}", RowKey = dateHour, Hour = currentHour, School = school };
  242. if (scope.Equals("teacher"))
  243. {
  244. hourLoginSc.Teacher = 1;
  245. hourLoginSc.Student = 0;
  246. hourLoginSc.TmdUser = 0;
  247. }
  248. else if (scope.Equals("student"))
  249. {
  250. hourLoginSc.Teacher = 0;
  251. hourLoginSc.Student = 1;
  252. hourLoginSc.TmdUser = 0;
  253. }
  254. else
  255. {
  256. hourLoginSc.Teacher = 0;
  257. hourLoginSc.Student = 0;
  258. hourLoginSc.TmdUser = 1;
  259. }
  260. try
  261. {
  262. await table.SaveOrUpdate<HourLoginSchool>(hourLoginSc);//保存在线数据
  263. }
  264. catch
  265. {
  266. }
  267. }
  268. //学校天峰值
  269. List<DayLoginSchool> DayLoginSchools = await table.QueryWhereString<DayLoginSchool>($"PartitionKey eq 'DayLogin-{school}' and RowKey eq '{dateDay}'");
  270. if (DayLoginSchools.Count > 0)
  271. {
  272. foreach (var dLoginSc in DayLoginSchools)
  273. {
  274. //dLoginSc.Day = currentDay;
  275. if (scope.Equals("teacher"))
  276. dLoginSc.Teacher += 1;
  277. else if (scope.Equals("student"))
  278. dLoginSc.Student += 1;
  279. else
  280. dLoginSc.TmdUser += 1;
  281. }
  282. try
  283. {
  284. await table.SaveOrUpdateAll(DayLoginSchools);
  285. }
  286. catch
  287. {
  288. }
  289. }
  290. else
  291. {
  292. //学校天峰值
  293. DayLoginSchool dayLoginSc = new() { PartitionKey = $"DayLogin-{school}", RowKey = dateDay, Day = currentDay, School = school };
  294. if (scope.Equals("teacher"))
  295. {
  296. dayLoginSc.Teacher = 1;
  297. dayLoginSc.Student = 0;
  298. dayLoginSc.TmdUser = 0;
  299. }
  300. else if (scope.Equals("student"))
  301. {
  302. dayLoginSc.Teacher = 0;
  303. dayLoginSc.Student = 1;
  304. dayLoginSc.TmdUser = 0;
  305. }
  306. else
  307. {
  308. dayLoginSc.Teacher = 0;
  309. dayLoginSc.Student = 0;
  310. dayLoginSc.TmdUser = 1;
  311. }
  312. try
  313. {
  314. await table.SaveOrUpdate<DayLoginSchool>(dayLoginSc);//保存在线数据
  315. }
  316. catch
  317. {
  318. }
  319. }
  320. }
  321. return loginInfos;
  322. }
  323. public static async Task<(string ip, string region)> LoginIp(HttpContext httpContext, IPSearcher _searcher)
  324. {
  325. var IpPort = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
  326. if (string.IsNullOrEmpty(IpPort))
  327. {
  328. IpPort = httpContext.Connection.RemoteIpAddress.ToString();
  329. }
  330. if (IpPort.Contains("::"))
  331. {
  332. IpPort = "127.0.0.1";
  333. }
  334. string ip = IpPort.Split(":")[0];
  335. string region = await _searcher.SearchIpAsync(ip);
  336. region= region.Replace("中国·", "").Replace("中国","").Replace("台湾省", "台湾");
  337. return (ip, region);
  338. }
  339. public static void LoginLog(HttpContext httpContext, Option _option, ILogger _logger, DingDing _dingDing, string ip, string region, string id, string name, int status)
  340. {
  341. httpContext.Request.Headers.TryGetValue("referer", out var referer);
  342. httpContext.Request.Headers.TryGetValue("sec-ch-ua", out var chua);
  343. httpContext.Request.Headers.TryGetValue("sec-ch-ua-platform", out var platform);
  344. httpContext.Request.Headers.TryGetValue("user-agent", out var useragent);
  345. if (status == 200)
  346. {
  347. string msg = $"{_option.Location} -- {name}({id}):Login Succeed! --Time:{DateTimeOffset.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")} " +
  348. $"--Browser Info( --referer:{referer} --sec-ch-ua:{chua} --sec-ch-ua-platform:{platform} --user-agent:{useragent} --ip:{ip} --region:{region} )";
  349. _logger.LogInformation(msg);
  350. }
  351. else
  352. {
  353. string msg = $"{_option.Location} -- {name}({id}):Login Failed! --Time:{DateTimeOffset.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")} " +
  354. $"--Browser Info( --referer:{referer} --sec-ch-ua:{chua} --sec-ch-ua-platform:{platform} --user-agent:{useragent} --ip:{ip} --region:{region} )";
  355. _ = _dingDing.SendBotMsg($"IES5,{_option.Location},{msg}", GroupNames.醍摩豆服務運維群組);
  356. _logger.LogError(msg);
  357. }
  358. }
  359. }
  360. }