菜鸟合作伙伴日志接入规范之C#实现
由于行业的业务功能需要,需要与菜鸟对接登录日志,将我们系统的用户登录信息提交给菜鸟,菜鸟分析通过分析日志,检查存在的一些安全问题。根据菜鸟提供的标准,实现了C#的接入,下面分享给大家,让需要的朋友少走些弯路。
/// <summary> /// 向菜鸟提交登录日志 /// </summary> /// <param name="loginLogEntity">登录日志实体</param> private static void SendLoginLog(BaseLoginLogEntity loginLogEntity) { /* appId 御城河应用标识 和御城河appKey值一样 appKey 御城河appKey method 日志类型(标识) express_login time 上传日志的时间 yyyy-MM-dd HH:mm:ss格式 operation_time 操作时间 yyyy-MM-dd HH:mm:ss格式 company 公司名称 公司名全称 station_id 站点id 例如:14214 station 站点名称 例如:xxx数据中心 province 站点所在省份 注:勿根据IP地址计算,要记录注册地址。例如:浙江 city 站点所在城市 注:勿根据IP地址计算,要记录注册地址。例如:杭州 user_id 操作员账号ID user 操作员账号名 source_type 发起请求的终端应用类型 web、client、ios、android、database source_application 发起请求的应用 如果是从数据库直接登陆数据库(source_type=Database),则记数据库名。如果是登陆系统,记录发起登录请求的应用(source_type=web、client、ios或android),若有跳转或通过单点登录方式登录,记录跳转前的应用名称;否则source_application应和target_application一致。 source_public_ip(*) 登陆操作源公网IP 如果请求通过公网,记录来源的公网IP,如:xxx.xxx.xxx.xxx source_private_ip(*) 登陆操作源内网IP 如果使用了NAT转换,记录内网IP,如:192.168.xxx.xxx source_vpn_ip(*) 登陆操作源VPN IP 如果使用了vpn,使用vpn分配的IP,如:192.168.xxx.xxx source_mac 源MAC地址 如果是CS架构则记录,BS架构无需记录 target_application 登录的目标应用 如果从数据库直接登陆数据库(source_type=Database),则记数据库名。如果登录系统(source_type=web、client、ios或android),则记录登录的目标系统名称,若有跳转或通过单点登录方式登录,记录跳转后的系统名称;否则target_application应和source_application一致。 target_public_ip(*) 登陆目标端公网IP 如果通过公网访问目标,记录目标的公网IP。如:xxx.xxx.xxx.xxx target_private_ip(*) 登陆目标端内网IP 如果目标进行了NAT转换或使用了负载均衡,记录目标的内网IP,如:192.168.xxx.xxx operation_type 操作类型 login/logout(两种类型必须记录) result 操作结果 success/fail(两种类型必须记录) reason 结果原因 当登录失败,或者退出时记录原因。例如timeout,password error等 feature 预留拓展字段 用键值对记录拓展字段,英文分号隔开 1. 获取御城河appKey 和appSecret 2. 按日志规范准备传入的字段参数(以UTF-8格式编码) 3. 计算signValue; 1) 针对上面准备的参数按照key进行排序(升序)然后拼接字符串 appSecretappId******appKey******company******computer_nameit-230000.xx.com……method******time******appSecret 注:将上面字符串中的红色字体替换成对应的值;最前面和最后面的appSecret处填写自己的appSecret。 2) 获取拼接字符串的UTF-8编码字节序列,采用md5方式加密,再把加密后的字节转化为16进制,得到sign字符串。 4. 对要传输的内容进行编码: 对参入的每个参数值做URL编码,这里的参数不要求顺序,但是必须对参数值进行url编码;尾部加上&sign=signValue。 appId=urlencode(appKeyValue)&…&time=urlencode(timeValue)&sign=signValue; 5. 推送数据 1) 使用post方法请求服务 http://gw.ose.aliyun.com/event/ecoLog?加上4步骤产生的字符串; POST请求的ContentType设置为:application/x-www-form-urlencoded。 2) API返回值 所有API返回json字符串,表示调用成功与否,格式如下:{"result":"success","errMsg":""} */ string appId = "12111"; string appSecret = "abcter"; Dictionary<string, object> dict = new Dictionary<string, object>(); dict.Add("appId", appId); dict.Add("appKey", appId); dict.Add("method", "express_login"); DateTime createOn = loginLogEntity.CreateOn ?? DateTime.Now; dict.Add("time", createOn.ToString(BaseSystemInfo.DateTimeFormat)); dict.Add("operation_time", createOn.ToString(BaseSystemInfo.DateTimeFormat)); dict.Add("company", "XXX公司"); dict.Add("station_id", loginLogEntity.CompanyId); dict.Add("station", loginLogEntity.CompanyName); dict.Add("province", loginLogEntity.Province); dict.Add("city", loginLogEntity.City); dict.Add("user_id", loginLogEntity.UserId); dict.Add("user", loginLogEntity.UserName); dict.Add("source_type", loginLogEntity.SourceType); dict.Add("source_application", loginLogEntity.SourceApplication); dict.Add("target_application", loginLogEntity.TargetApplication); dict.Add("source_public_ip", loginLogEntity.IPAddress); dict.Add("source_mac", loginLogEntity.MACAddress); dict.Add("operation_type", loginLogEntity.OperationType == 1 ? "login" : "logout"); dict.Add("result", loginLogEntity.Result == 1 ? "success" : "fail"); dict.Add("reason", loginLogEntity.LoginStatus); dict.Add("feature", string.Empty); var dicSort = from objDic in dict orderby objDic.Key ascending select objDic; StringBuilder sb = new StringBuilder(); sb.Append(appSecret); List<string> list = new List<string>(); foreach (KeyValuePair<string, object> kvp in dicSort) { sb.Append(kvp.Key + kvp.Value); list.Add(kvp.Key + "=" + System.Web.HttpUtility.UrlEncode(kvp.Value.ToString(), Encoding.UTF8)); } string parameters = string.Join("&", list); sb.Append(appSecret); string signValue = sb.ToString(); MD5 md5 = MD5.Create(); byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(signValue)); string result = string.Empty; for (int i = 0; i < hashBytes.Length; i++) { //X 表是10进制,X2表示16进制 result += hashBytes[i].ToString("x2"); } signValue = result; // 线程提交 ThreadPool.QueueUserWorkItem(delegate { try { string url = "http://gw.ose.aliyun.com/event/ecoLog?" + parameters + "&sign=" + signValue; var request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.GetResponse(); var response = (HttpWebResponse)request.GetResponse(); using (var stream = response.GetResponseStream()) { if (stream != null) { var responseString = new StreamReader(stream).ReadToEnd(); if (!string.IsNullOrWhiteSpace(responseString)) { NLogHelper.Trace("向菜鸟推送登录日志,登录人:" + loginLogEntity.UserName + ",推送结果:" + responseString); } } } } catch (Exception ex) { NLogHelper.Warn(ex, "向菜鸟推送登录日志出现异常:"+ex.Message); } }); }