API-接口安全签名(二)

        在做项目的时候,大家都都会遇到调用其他项目接口,或者被其他项目接口调用,这里面就会涉及到 网络传输过程,数据在网络转输的过程中如何保证数据的安全,

遇到的问题:

1:数据被拦截后,就可以获取调用接口的方法,以及参数信息,这个时候如果设计到一些私密信息,就会信息泄露

2:如果被拦截后被恶意攻击,那么服务就会导致内存溢出,甚至服务瘫痪,这种情况严重的会直接导致业务无法进行

3:如果设计到update 或者insert的api接口时,跟金额或者其他有关的信息,那么问题之大就不言而喻了。

如何避免这些问题的出现。目前 淘宝,京东 各大平台做的都是根据  时间戳 +数字签名+key-session验证

如何实现签名:直接上代码,如下图:

这个项目是.Net  Core2.1,如果是用Formwork4.5 框架 获取FW的其他框架,原理也是一样的,除了里面的一些代码有些小区别,其他的没有任何区别。

一:在项目里面新建一个文件夹:Filters  :这个文件夹就是用来控制数字签名的。里面新建3个类,ActionFilter ,ExperienceFilter,ValidFilter  

 

 

二:在调用任何接口的时候,都需要先执行  ActionFilter类中的方法:OnActionExecuting

所以这里需要注意:需要继承类:ActionFilterAttribute

开始执行之前:OnActionExecuting

结束接口调用执行方法:OnActionExecuted

如图:

代码如下:

/// <summary>
    /// 基础过滤器,用于记录每个接口请求参数,执行时间 
    /// </summary>
    public class ActionFilter : ActionFilterAttribute
    {
        /// <summary>
        /// 第三方调用方
        /// </summary>
        public TenantModel Tenant { get; set; }

        /// <summary>
        /// 开始执行之前
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            string controllerName = context.RouteData.Values["controller"].ToString();
            string actionName = context.RouteData.Values["action"].ToString();
 
            //测试
            if (controllerName.Equals("Valadate"))
            {
                base.OnActionExecuting(context);
                return;
            }
            GetTimer(context, "action").Start();
            if (context.ActionArguments.Count <= 0)
            {
                context.Result = new JsonResult(new BaseResponse { Code = ResCode.Parameter_ConvertFail, Message = ResMsg.Parameter_ConvertFail });
                return;
            }
            //请求日志
            var arguments = context.ActionArguments["request"];
            string argumentsStr = arguments == null ? "无" : JsonConvertHelper.SerializeToCamelCase(arguments);
            CommonLogInfo logInfo = new CommonLogInfo();
            logInfo.LogType = LogMessageType.Info;
            logInfo.ClassName = controllerName;
            logInfo.MethodName = actionName;
            logInfo.Message = string.Format("请求【{0}/{1}】开始。参数:{2}", controllerName, actionName, argumentsStr);
            logInfo.CallIP = GetHostAddress(context);
            AppLog.Write(logInfo);

            //校验方法参数是否为空
            bool b = !ValidFilter.CheckPara(actionName, argumentsStr);
            if (b)
            {
                AppLog.Write("参数无效,必填参数为空!", LogMessageType.Error);
                context.Result = new JsonResult(new BaseResponse { Code = ResCode.Parameter_Invalid, Message = "参数无效,必填参数不能为空!" });
                return;
            }

            //非法请求
            if (arguments == null)
            {
                context.Result = new JsonResult(new BaseResponse { Code = ResCode.System_ErrorRequest, Message = ResMsg.System_ErrorRequest });
                return;
            }
            BaseRequest baseRequest = arguments as BaseRequest;
            //有效期校验
            if (DateTime.TryParseExact(baseRequest.TimeSpan, "yyyyMMddHHmmss", new CultureInfo("zh-CN", true), DateTimeStyles.None, out DateTime requestData))
            {
                DateTime nowDate = DateTime.UtcNow.AddHours(8);
                //测试
                if (requestData > nowDate.AddMinutes(120) || requestData < nowDate.AddMinutes(-120))
                {
                    context.Result = new JsonResult(new BaseResponse
                    {
                        Code = ResCode.ClientTime_Error,
                        Message = "请求时间戳无效" + requestData.ToString("yyyy-MM-dd HH:mm:ss") + "/" + nowDate.ToString("yyyy-MM-dd HH:mm:ss"),
                        TimeSpan = DateTime.UtcNow.AddHours(8).ToString("yyyyMMddHHmmss")
                    });
                    return ;
                }
            }
            else
            {
                context.Result = new JsonResult(new BaseResponse { Code = ResCode.Parameter_Invalid, Message = "请求无效" });
                return;
            }
            //获取密钥

            string Secretkey = new ClientFactory().Secretkey(baseRequest.AppId);
            if (Secretkey == "undefined")
            {
                context.Result = new JsonResult(new BaseResponse { Code = ResCode.ClientVerification_Error, Message = "无效AppId" });
                return;

            }
            //TenantModel tenant =new IpInfo().FindTenantModel(baseRequest.AppId);
            //if (tenant == null)
            //{
            //    context.Result = new JsonResult(new BaseResponse { Code = ResCode.ClientVerification_Error, Message = "无效AppId" });
            //    return;
            //}
            //Tenant = tenant;
            //验签
            if (!SignUtil.MD5Verify(arguments, baseRequest.Sign, Secretkey))
            {
                context.Result = new JsonResult(new BaseResponse { Code = ResCode.ClientVerification_Error, Message = "验签失败" });
                return;
            }
            //获取酒店
            //YiBonHotelMapEntity entity = BLL_Hotel.QueryYiBonHotelMapList(baseRequest.HotelCode);
            //if (entity == null)
            //{
            //    context.Result = new JsonResult(new BaseResponse { Code = ResCode.Parameter_Invalid, Message = "无效的酒店编号" });
            //    return;
            //}
            //baseRequest.HotelCode = entity.HotelCode;
            base.OnActionExecuting(context);
        }

        /// <summary>
        /// 结束
        /// </summary>
        /// <param name="context"></param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            string controllerName = context.RouteData.Values["controller"].ToString();
            string actionName = context.RouteData.Values["action"].ToString();
            if (controllerName.Equals("Valadate"))
            {
                base.OnActionExecuted(context);
                return;
            }
            BaseResponse baseResponse = null;
            if (context.Result is ObjectResult)
            {
                baseResponse = (context.Result as ObjectResult).Value as BaseResponse;
            }
            else if (context.Result is JsonResult)
            {
                baseResponse = (context.Result as JsonResult).Value as BaseResponse;
            }

            if (baseResponse != null)
            {
                baseResponse.TimeSpan = DateTime.UtcNow.AddHours(8).ToString("yyyyMMddHHmmss");
                baseResponse.Sign = SignUtil.MD5Sign(baseResponse, Tenant.Secretkey);
                context.Result = new JsonResult(baseResponse);
                var stopwatch = GetTimer(context, "action");
                stopwatch.Stop();
                int duration = (int)stopwatch.ElapsedMilliseconds; //执行时间


                CommonLogInfo logInfo = new CommonLogInfo();
                logInfo.LogType = LogMessageType.Info;
                logInfo.ClassName = controllerName;
                logInfo.MethodName = actionName;
                logInfo.Message = string.Format("响应【{0}/{1}】结束。耗时:{2}毫秒 参数:{3}", controllerName, actionName, duration, JsonConvertHelper.SerializeToCamelCase(baseResponse));
                logInfo.CallIP = GetHostAddress(context);
                logInfo.Duration = duration;
                AppLog.Write(logInfo);
            }
            base.OnActionExecuted(context);
        }
        /// <summary>
        /// 获取客户端IP地址(无视代理)
        /// </summary>
        /// <returns>若失败则返回回送地址</returns>
        private string GetHostAddress(FilterContext context)
        {
            return context.HttpContext.Connection.RemoteIpAddress.ToString();
        }
        private Stopwatch GetTimer(FilterContext context, string name)
        {
            string key = "timer_" + name;
            if (context.HttpContext.Items.Keys.Contains(key))
            {
                return (Stopwatch)context.HttpContext.Items[key];
            }
            var stopwatch = new Stopwatch();
            context.HttpContext.Items[key] = stopwatch;
            return stopwatch;
        }
    }

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值