平安校园
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.

DatabaseLoggingWriter.cs 8.0 KiB

4 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. 
  2. //
  3. using Masuit.Tools;
  4. using Microsoft.Extensions.Logging;
  5. using NewLife.Serialization;
  6. using SqlSugar;
  7. using System.Globalization;
  8. using UAParser;
  9. namespace SafeCampus.Web.Core;
  10. /// <summary>
  11. /// 数据库写入器
  12. /// </summary>
  13. public class DatabaseLoggingWriter : IDatabaseLoggingWriter
  14. {
  15. private readonly ISearcher _searcher;
  16. private readonly SqlSugarScope _db;
  17. private readonly ILogger<DatabaseLoggingWriter> _logger;
  18. public DatabaseLoggingWriter(ILogger<DatabaseLoggingWriter> logger, ISearcher searcher)
  19. {
  20. _db = DbContext.DB;
  21. _logger = logger;
  22. _searcher = searcher;
  23. }
  24. public async Task WriteAsync(LogMessage logMsg, bool flush)
  25. {
  26. //获取请求json字符串
  27. var jsonString = logMsg.Context.Get("loggingMonitor").ToString();
  28. //转成实体
  29. var loggingMonitor = jsonString.ToJsonEntity<LoggingMonitorJson>();
  30. //日志时间赋值
  31. loggingMonitor.LogDateTime = logMsg.LogDateTime;
  32. // loggingMonitor.ReturnInformation.Value
  33. //验证失败和没有DisplayTitle之类的不记录日志
  34. if (loggingMonitor.Validation == null && loggingMonitor.DisplayTitle != null)
  35. {
  36. //获取操作名称
  37. var operation = loggingMonitor.DisplayTitle;
  38. var client = (ClientInfo)logMsg.Context.Get(LoggingConst.CLIENT);//获取客户端信息
  39. var path = logMsg.Context.Get(LoggingConst.PATH).ToString();//获取操作名称
  40. var method = logMsg.Context.Get(LoggingConst.METHOD).ToString();//获取方法
  41. //表示访问日志
  42. if (operation == EventSubscriberConst.LOGIN_B || operation == EventSubscriberConst.LOGIN_OUT_B)
  43. {
  44. //如果没有异常信息
  45. if (loggingMonitor.Exception == null)
  46. {
  47. await CreateVisitLog(operation, loggingMonitor, client);//添加到访问日志
  48. }
  49. else
  50. {
  51. //添加到异常日志
  52. await CreateOperationLog(operation, path, loggingMonitor, client);
  53. }
  54. }
  55. else
  56. {
  57. //只有定义了Title的POST方法才记录日志
  58. if (!operation.Contains("/") && method == "POST")
  59. {
  60. //添加到操作日志
  61. await CreateOperationLog(operation, path, loggingMonitor, client);
  62. }
  63. }
  64. }
  65. }
  66. /// <summary>
  67. /// 创建访问日志
  68. /// </summary>
  69. /// <param name="operation">访问类型</param>
  70. /// <param name="loggingMonitor">loggingMonitor</param>
  71. /// <param name="clientInfo">客户端信息</param>
  72. private async Task CreateVisitLog(string operation, LoggingMonitorJson loggingMonitor, ClientInfo clientInfo)
  73. {
  74. string name;//用户姓名
  75. string opAccount;//用户账号
  76. if (operation == EventSubscriberConst.LOGIN_B)
  77. {
  78. //如果是登录,用户信息就从返回值里拿
  79. var result = loggingMonitor.ReturnInformation.Value.ToJson();//返回值转json
  80. var userInfo = result.ToJsonEntity<SafeCampusResult<SysUser>>();//格式化成user表
  81. name = userInfo.Data.Name;//赋值姓名
  82. opAccount = userInfo.Data.Account;//赋值账号
  83. }
  84. else
  85. {
  86. //如果是登录出,用户信息就从AuthorizationClaims里拿
  87. name = loggingMonitor.AuthorizationClaims.Where(it => it.Type == ClaimConst.NAME).Select(it => it.Value).FirstOrDefault();
  88. opAccount = loggingMonitor.AuthorizationClaims.Where(it => it.Type == ClaimConst.ACCOUNT).Select(it => it.Value).FirstOrDefault();
  89. }
  90. //日志表实体
  91. var devLogVisit = new SysLogVisit
  92. {
  93. Name = operation,
  94. Category = operation == EventSubscriberConst.LOGIN_B ? CateGoryConst.LOG_LOGIN : CateGoryConst.LOG_LOGOUT,
  95. ExeStatus = SysLogConst.SUCCESS,
  96. OpAddress = GetLoginAddress(loggingMonitor.RemoteIPv4),
  97. OpIp = loggingMonitor.RemoteIPv4,
  98. OpBrowser = clientInfo.UA.Family + clientInfo.UA.Major,
  99. OpOs = clientInfo.OS.Family + clientInfo.OS.Major,
  100. OpTime = loggingMonitor.LogDateTime,
  101. OpUser = name,
  102. OpAccount = opAccount
  103. };
  104. await _db.CopyNew().InsertableWithAttr(devLogVisit).IgnoreColumns(true).SplitTable().ExecuteCommandAsync();//入库
  105. }
  106. /// <summary>
  107. /// 创建操作日志
  108. /// </summary>
  109. /// <param name="operation">操作名称</param>
  110. /// <param name="path">请求地址</param>
  111. /// <param name="loggingMonitor">loggingMonitor</param>
  112. /// <param name="clientInfo">客户端信息</param>
  113. /// <returns></returns>
  114. private async Task CreateOperationLog(string operation, string path, LoggingMonitorJson loggingMonitor,
  115. ClientInfo clientInfo)
  116. {
  117. //用户名称
  118. var name = loggingMonitor.AuthorizationClaims?.Where(it => it.Type == ClaimConst.NAME).Select(it => it.Value).FirstOrDefault();
  119. //账号
  120. var opAccount = loggingMonitor.AuthorizationClaims?.Where(it => it.Type == ClaimConst.ACCOUNT).Select(it => it.Value).FirstOrDefault();
  121. //获取参数json字符串,
  122. var paramJson = loggingMonitor.Parameters == null || loggingMonitor.Parameters.Count == 0
  123. ? null
  124. : loggingMonitor.Parameters[0].Value.ToJsonString();
  125. //获取结果json字符串
  126. var resultJson = string.Empty;
  127. if (loggingMonitor.ReturnInformation != null)//如果有返回值
  128. {
  129. if (loggingMonitor.ReturnInformation.Value != null)//如果返回值不为空
  130. {
  131. var time = loggingMonitor.ReturnInformation.Value.Time != null
  132. ? DateTime.Parse(loggingMonitor.ReturnInformation.Value.Time)
  133. : DateTime.Now;//转成时间
  134. loggingMonitor.ReturnInformation.Value.Time = time.ToString(CultureInfo.CurrentCulture);//转成字符串
  135. resultJson = loggingMonitor.ReturnInformation.Value.ToJsonString();
  136. }
  137. }
  138. //操作日志表实体
  139. var devLogOperate = new SysLogOperate
  140. {
  141. Name = operation,
  142. Category = CateGoryConst.LOG_OPERATE,
  143. ExeStatus = SysLogConst.SUCCESS,
  144. OpAddress = GetLoginAddress(loggingMonitor.RemoteIPv4),
  145. OpIp = loggingMonitor.RemoteIPv4,
  146. OpBrowser = clientInfo.UA.Family + clientInfo.UA.Major,
  147. OpOs = clientInfo.OS.Family + clientInfo.OS.Major,
  148. OpTime = loggingMonitor.LogDateTime,
  149. OpUser = name,
  150. OpAccount = opAccount,
  151. ReqMethod = loggingMonitor.HttpMethod,
  152. ReqUrl = path,
  153. ResultJson = resultJson,
  154. ClassName = loggingMonitor.DisplayName,
  155. MethodName = loggingMonitor.ActionName,
  156. ParamJson = paramJson
  157. };
  158. //如果异常不为空
  159. if (loggingMonitor.Exception != null)
  160. {
  161. devLogOperate.Category = CateGoryConst.LOG_EXCEPTION;//操作类型为异常
  162. devLogOperate.ExeStatus = SysLogConst.FAIL;//操作状态为失败
  163. devLogOperate.ExeMessage = loggingMonitor.Exception.Type + ":" + loggingMonitor.Exception.Message + "\n"
  164. + loggingMonitor.Exception.StackTrace;
  165. }
  166. await _db.CopyNew().InsertableWithAttr(devLogOperate).IgnoreColumns(true).SplitTable().ExecuteCommandAsync();//入库
  167. }
  168. /// <summary>
  169. /// 解析IP地址
  170. /// </summary>
  171. /// <param name="ip"></param>
  172. /// <returns></returns>
  173. private string GetLoginAddress(string ip)
  174. {
  175. var loginAddress = "未知";
  176. try
  177. {
  178. var ipInfo = _searcher.Search(ip);//解析ip
  179. loginAddress = ipInfo?.Replace("0|", "");//去掉前面的0|
  180. }
  181. catch (global::System.Exception ex)
  182. {
  183. _logger.LogError("IP解析错误" + ex, ex);
  184. }
  185. return loginAddress;
  186. }
  187. }