平安校园
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

206 lines
8.0 KiB

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