.net ActionFilterAttribute 统一校验外部api签名 md5生成签名

本文介绍如何在.NET中使用ActionFilterAttribute进行API请求的统一校验,特别是针对外部API的MD5签名验证过程。通过Controller的action标记,确保只有验签通过的请求才能访问指定的方法。详细讲解了将类实体属性转化为键值对、MD5加密及ASCII排序、HTTP POST请求的实现步骤,以及外部如何生成签名并发起请求。
  1. 利用ActionFilterAttribute解析外部接受数据,并验签
/// <summary>
    /// 外部api请求时,进行签名校验
    /// </summary>
    public class ExterApiFilter : ActionFilterAttribute
    {
        string token = "abc@#";

        /// <summary>
        /// 进入系统,对外部请求的进行验签操作
        /// 1、除签名外字段按ASCII码从小到大排序
        /// 2、最后连接私有的token
        /// 3、按key=value形式拼接
        /// 4、签名校验
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            try
            {
                //入参解析
                var paras = filterContext.ActionParameters;
                var i = filterContext.ActionDescriptor.GetParameters();
                Dictionary<string, object> inParamDics = new Dictionary<string, object>();//入参集合
                foreach (var item in i)
                {
                    var itemType = item.ParameterType;
                    if (itemType.IsClass && !itemType.Name.Equals("String", System.StringComparison.OrdinalIgnoreCase))//类
                    {
                        GetPropertyDic(inParamDics, itemType.GetProperties(), filterContext.ActionParameters[item.ParameterName]);
                    }
                    else
                    {
                        if (!inParamDics.ContainsKey(item.ParameterName)) inParamDics.Add(item.ParameterName, filterContext.Controller.ValueProvider.GetValue(item.ParameterName).AttemptedValue);
                    }
                }

                Dictionary<string, string> inParam = new Dictionary<string, string>();
                string sign = string.Empty;
                #region 解析数据
                if (inParamDics.Keys.Contains("sign"))
                {
                    sign = inParamDics["sign"]?.ToString();
                }
                inParam = inParamDics.Where(x => !string.IsNullOrEmpty(x.Value?.ToString())).ToDictionary(k => k.Key, k => k.Value?.ToString());

                if (inParam.ContainsKey("sign")) inParam.Remove("sign");

                var signScret = new Dictionary<string, string>() { ["token"] = token };
                #endregion 解析数据
                bool isCkSign = !string.IsNullOrEmpty(sign) && KosSigns.GetMd5Sign(inParam, signScret).Equals(sign, System.StringComparison.OrdinalIgnoreCase);
                if (!isCkSign)
                {
                    filterContext.Result = new JsonResult() { Data = new { Result = false, Message = "验签失败" } };
                }
            }
            catch (Exception ex)
            {
                filterContext.Result = new JsonResult() { Data = new { Result = false, Message = "内部错误" } };
            }
            base.OnActionExecuting(filterContext);
        }
        /// <summary>
        /// 实体类解析成键值对
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="inParam">入参</param>
        /// <param name="infos">实体的属性集合</param>
        /// <param name="entity">实体</param>
        private void GetPropertyDic<T>(Dictionary<string, object> inParam, PropertyInfo[] infos, T entity)
        {
            foreach (var info in infos)
            {
                var itemTpe = info.PropertyType;
                if (itemTpe.IsClass && !itemTpe.Name.Equals("String", StringComparison.OrdinalIgnoreCase))
                {
                    if (info.GetValue(entity) == null) continue;
                    GetPropertyDic(inParam, itemTpe.GetProperties(), info.GetValue(entity));
                }
                else
                {
                    inParam.Add(info.Name, info.GetValue(entity, null));
                }
            }
        }
    }

2.Controller中的action标记,验签通过后的方法请求。供外部请求http://localhost:80/ApiFilter/GetApiFilter

       

 [ExterApiFilter]
        public JsonResult GetApiFilter(GetApiFilterInput input)
        {
            bool resultStatus = false;
            //入参判断
            if (string.IsNullOrEmpty(input.Name)) return Json(new { Result = false, Message = "名称不能为空" });
            //查询数据
            var outputs = _iService.GetApiFilter(input);

            resultStatus = outputs != null && outputs.TotalCount > 0;
            if (!resultStatus) Json(new { Result = resultStatus, Message = "无相关数据" });

            return Json(new { Result = resultStatus, Data = outputs });
        }

3. 私有方法之:类实体的属性与值转化成键值对形式

     

  /// <summary>
        /// 类实体的属性与值转化成键值对形式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="inParam"></param>
        /// <param name="infos"></param>
        /// <param name="Entity"></param>
        private static void GetEntityPropertyToDic<T>(Dictionary<string, object> inParam, PropertyInfo[] infos, T Entity)
        {
            foreach (var info in infos)
            {
                var itemTpe = info.PropertyType;
                //实体中有嵌套类的处理
                if (itemTpe.IsClass && !itemTpe.Name.Equals("String", StringComparison.OrdinalIgnoreCase))
                {
                    if (info.GetValue(Entity) == null) continue;
                    GetEntityPropertyToDic(inParam, itemTpe.GetProperties(), info.GetValue(Entity));
                }
                else
                {
                    inParam.Add(info.Name, info.GetValue(Entity, null));
                }
            }
        }

4.私有方法之:Md5加密,并且参数ASCII码排序

       

 /// <summary>
        /// Md5加密
        /// </summary>
        /// <param name="param"></param>
        /// <param name="signScret"></param>
        /// <returns></returns>
        private static string GetMd5Sign(Dictionary<string, string> param, Dictionary<string, string> signScret)
        {
            var sign_s = ComSecurity.GetASCIIParamMap(param);
            if (signScret != null && signScret.Any())
            {
                foreach (var item in signScret)
                {
                    sign_s = sign_s + $"&{item.Key}=" + item.Value;
                }
            }
            return ComSecurity.Md5Encrypt(sign_s);
        }

5.私有方法之:http的post请求

private static string GetPostUrl(string url, string postData, Dictionary<string, string> heardsDic = null)
        {
            string result = string.Empty;
            try
            {
                HttpWebRequest request = null;
                if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
                {
                    request = WebRequest.Create(url) as HttpWebRequest;
                    ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                    request.ProtocolVersion = HttpVersion.Version11;
                    // 这里设置了协议类型。
                    ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;// SecurityProtocolType.Tls1.2; 
                    request.KeepAlive = false;
                    ServicePointManager.CheckCertificateRevocationList = true;
                    ServicePointManager.DefaultConnectionLimit = 100;
                    ServicePointManager.Expect100Continue = false;
                }
                else
                {
                    request = (HttpWebRequest)WebRequest.Create(url);
                }

                request.Method = "POST";    //使用get方式发送数据
                request.ContentType = "application/json";
                request.Referer = null;
                request.AllowAutoRedirect = true;
                request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
                request.Accept = "*/*";
                #region 请求头数据
                if (heardsDic != null)
                {
                    foreach (var item in heardsDic)
                    {
                        SetHeaderValue(request.Headers, item.Key, item.Value);
                    }
                }
                #endregion 请求头数据
                byte[] data = Encoding.UTF8.GetBytes(postData);
                Stream newStream = request.GetRequestStream();
                newStream.Write(data, 0, data.Length);
                newStream.Close();

                //获取网页响应结果
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream stream = response.GetResponseStream();
                using (StreamReader sr = new StreamReader(stream))
                {
                    result = sr.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
            }
            return result;
        }
        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受  
        }
        private static void SetHeaderValue(WebHeaderCollection header, string name, string value)
        {
            var property = typeof(WebHeaderCollection).GetProperty("InnerCollection", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            if (property != null)
            {
                var collection = property.GetValue(header, null) as NameValueCollection;
                collection[name] = value;
            }
        }

6.外部生成签名并发起请求

         

​
  //签名 私钥
            string token = "abc@#";

var data= new TestManageDemo() { Id = 10, Age = 20, Name = "少侠", Address = "天涯海角路", Interest = new TestInterest() { InterestName = "仗剑撸代码", InterestAge = 9 } };

            //反射
            Type type = data.GetType();
            System.Reflection.PropertyInfo[] propertyInfos = type.GetProperties();
            Dictionary<string, string> inParam = new Dictionary<string, string>();
            Dictionary<string, object> inParamDics = new Dictionary<string, object>();
            //类实体转键值对
            GetEntityPropertyToDic(inParamDics, propertyInfos, data);

            inParam = inParamDics.ToDictionary(k => k.Key, k => k.Value?.ToString());
            if (inParam.ContainsKey("sign")) inParam.Remove("sign");
            //md5签名
            data.sign = GetMd5Sign(inParam, new Dictionary<string, string>() { ["token"] = token });
            //http请求
            st = GetPostUrl("http://localhost:80/ApiFilter/GetApiFilter", JsonConvert.SerializeObject(data));

​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值