在做项目的时候,大家都都会遇到调用其他项目接口,或者被其他项目接口调用,这里面就会涉及到 网络传输过程,数据在网络转输的过程中如何保证数据的安全,
遇到的问题:
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;
}
}