using System; using System.Collections.Generic; using System.Diagnostics; using System.Dynamic; using System.Linq; using Hh.Mes.Api; using Hh.Mes.Common.config; using Hh.Mes.Common.Json; using Hh.Mes.Common.log; using Hh.Mes.POJO.Entity; using Hh.Mes.Pojo.System; using Hh.Mes.Service.Logs; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Net.Http.Headers; using Microsoft.Extensions.Caching.Distributed; using Newtonsoft.Json; using JsonSerializer = System.Text.Json.JsonSerializer; namespace Hh.Mes.API.AOP { /// <summary> /// 全局登入token认证 验证 /// </summary> public class AuthFilterAttribute : ActionFilterAttribute { #region 属性 private readonly string ReturnMsgTokens = "{\"code\":401,\"status\":false,\"message\":\"Tokens失效 请重新登入\",\"result\":null}"; private string requestContext { get; set; } private Stopwatch Stopwatch { get; set; } private UserAuthSession user { get; set; } private string token { get; set; } private HttpRequest httpContext { get; set; } private ControllerActionDescriptor description { get; set; } private string ip { get; set; } private readonly string[] alloweLog = { "PdaOfflineMenu", "GetOrderState" }; private readonly IDistributedCache _cache; #endregion public AuthFilterAttribute(IDistributedCache cache) { _cache = cache; } public override void OnActionExecuting(ActionExecutingContext context) { #region 初始化 赋值 Stopwatch = new Stopwatch(); Stopwatch.Start(); httpContext = context.HttpContext.Request; description = (ControllerActionDescriptor)context.ActionDescriptor; requestContext = JsonConvert.SerializeObject(context.ActionArguments); if (requestContext == "{}" && httpContext.ContentType != null && httpContext.Method == "POST") { if (httpContext.ContentType.IndexOf("form-data", StringComparison.Ordinal) > -1) { requestContext = "{"; foreach (var item in context.HttpContext.Request.Form.Keys) { requestContext += item == "password" ? $"\"{item}\":\"{string.Concat(Enumerable.Repeat("*", context.HttpContext.Request.Form[item].ToString().Count()))}\"" : $"\"{item}\":\"{context.HttpContext.Request.Form[item]}\""; if (item != context.HttpContext.Request.Form.Keys.Last()) requestContext += ","; } requestContext += "}"; } } token = GetToken(context); ip = context.HttpContext.Connection.RemoteIpAddress.ToString(); #endregion #region 获取请求参数 写日志 //dynamic response; //if (httpContext.Method.ToLower() == "get") //{ // response = httpContext.QueryString.ToString(); //} //else //{ // dynamic result = context.Result; // response = IsPropertyExist(result, "Value") ? result.Value : "返回结果前"; //} //EnqueueInterLog(response, user?.Account); #endregion #region 忽略拦截 if (AopAllowed()) { base.OnActionExecuting(context); return; } #endregion #region token 读取 日志写入队列 if (string.IsNullOrEmpty(token)) { ContextResponse(context); Log4NetHelper.Instance.Info("tokens 为null"); } else { var userBytes = _cache.Get(token); UserAuthSession user = null; if (userBytes != null) { user = JsonSerializer.Deserialize<UserAuthSession>(userBytes); } if (user == null || string.IsNullOrWhiteSpace(user.Account)) { Log4NetHelper.Instance.Info("user 为null:" + token); ContextResponse(context); Stopwatch.Stop(); EnqueueInterLog(ReturnMsgTokens, ""); } } base.OnActionExecuting(context); #endregion } public override void OnActionExecuted(ActionExecutedContext context) { base.OnActionExecuted(context); Stopwatch.Stop(); #region 获取请求参数 写日志 dynamic response; var resultType = context.Result.GetType(); if (httpContext.Method.ToLower() == "get") { var objectResult = context.Result as ObjectResult; response = IsPropertyExist(objectResult, "Value") ? objectResult.Value : $"返回结果只处理JSON 格式,当前类型: {resultType}"; } else { dynamic result = context.Result; response = IsPropertyExist(result, "Value") ? result.Value : $"返回结果只处理JSON 格式,当前类型: {resultType}"; } var keyUrl = context.HttpContext.Request.Path.Value; EnqueueInterLog(response, user?.Account, keyUrl); #endregion #region 忽略拦截 if (AopAllowed()) return; #endregion } #region 自定义方法 private string GetToken(ActionExecutingContext context) { var temp = context.HttpContext.Request.Query[Program.tokens]; if (string.IsNullOrEmpty(temp)) temp = context.HttpContext.Request.Cookies[Program.tokens]; if (string.IsNullOrEmpty(temp)) temp = context.HttpContext.Request.Headers[Program.tokens]; return temp; } private void ContextResponse(ActionExecutingContext context) { context.HttpContext.Response.ContentType = "application/json"; context.Result = new ContentResult { Content = ReturnMsgTokens, StatusCode = StatusCodes.Status200OK, ContentType = "application/json" }; } /// <summary> /// 动态类型 dynamic 是否存在某个属性 /// </summary> private static bool IsPropertyExist(dynamic data, string propertyname) { try { if (data == null) return false; if (data is ExpandoObject) return ((IDictionary<string, object>)data).ContainsKey(propertyname); return data.GetType().GetProperty(propertyname) != null; } catch (Exception) { Log4NetHelper.Instance.Info("【AuthFilterAttribute、IsPropertyExist】方法异常,不影响程序运行,反复出现请检查程序"); return false; } } private void EnqueueInterLog(dynamic response, string name, string keyUrl = "") { var path = httpContext.Path.ToString(); if (alloweLog.Any(t => path.IndexOf(t, StringComparison.Ordinal) > -1)) return; var browser = httpContext.Headers[HeaderNames.UserAgent].ToString(); var system = "api"; if (browser.IndexOf("Android", StringComparison.Ordinal) > -1) system = "app Android"; bool isOk = response is string; if (!isOk) response = JsonHelper.Instance.Serialize(response); var type = "接收"; var isSaveLog = true; if (SystemVariable.apiList.Count == 0) SystemVariable.InitApiList(); if (!string.IsNullOrEmpty(keyUrl) && SystemVariable.apiList.ContainsKey(keyUrl)) { type = SystemVariable.apiList[keyUrl].Item1; isSaveLog = SystemVariable.apiList[keyUrl].Item2; } //InitApiList 配置false 不写入数据库队列日志 if (!isSaveLog) return; QueueInterLog.GetInstance.Queue().Enqueue(new sys_interface_log() { type = type, system = system, method = httpContext.Method, server = httpContext.Host.ToString(), path = path, apiGroup = description.ControllerName, actionName = description.ActionName, queryString = httpContext.QueryString.ToString(), request = requestContext, response = response, totalMilliseconds = Stopwatch.Elapsed.TotalSeconds, logTime = DateTime.Now, createBy = user == null ? system : user.Name, name = name, ip = ip, browser = browser, result = "token:" + token }); } /// <summary> /// 当前url 是否匹配 忽略拦截的 配置路径 /// </summary> /// <returns></returns> private bool AopAllowed() { var allowedUrl = ConfigRead.GetInstance.GetAppsetConnection().allowed; if (allowedUrl == null || allowedUrl.Length == 0) return false; var url = httpContext.Path.Value; return allowedUrl.Any(item => url.IndexOf(item, StringComparison.Ordinal) > -1); } #endregion } }