最近在跟菜鸟天地系统对接,业务中涉及到单点接入,感觉其实现思想很不错,现分享一下,供大家参考:
从CP内部系统进入菜鸟天地,也就是从菜鸟的合作伙伴(物流或快递公司内部系统)单点跳转进入菜鸟天地系统
红色的请求需要CP实现(合作方):
1、LINK接口( ):服务器端获取快速登录菜鸟的令牌(loginToken) CNUSER_GET_LOGIN_TOKEN 请求参数:员工工号 返回参数:loginToken
2、生成快速登录菜鸟的URL,并从浏览器发起302跳转 #*http://login.cainiao.com/cplogin.htm?loginToken=2nAiCDsSZVXBS8kLApj9iA&redirectUrl=http%3a%2f%2ffly.cainiao.com goto:登陆后的目标跳转地址。如菜鸟天地的地址为:http%3a%2f%2ffly.cainiao.com login_token:菜鸟返回的令牌(注意:login_token使用一次后即失效,且LINK接口返回起60秒后超时失效)
功能实现:用户在合作方系统登录后,访问菜鸟天地链接时调用菜鸟接口返回认证token,再构造地址跳转到菜鸟天地系统,token使用一次后失效
从合作方登录菜鸟天地
/// <summary> /// 登录菜鸟天地系统 /// </summary> /// <returns></returns> public ActionResult CaiNiaoTianDi() { string userCode = UserInfo.Code; try { JsonResult<string> result = CaiNiaoAPIUtilities.GetCaiNiaoLoginToken(userCode); if (result.Status) { string token = result.ResultValue; string url = string.Format("http://login.cainiao.com/cplogin.htm?loginToken={0}&redirectUrl=https://fly.cainiao.com", token); return Redirect(url); } else { return Content("登录菜鸟系统出错" + result.Data); } } catch (Exception ex) { NLogHelper.Warn(ex, "登录菜鸟系统异常"); return Content("登录菜鸟系统异常"); } }
/// <summary> /// 获取登录菜鸟系统的token /// </summary> /// <param name="userCode"></param> /// <returns></returns> public static JsonResult<string> GetCaiNiaoLoginToken(string userCode) { JsonResult<string> result = new JsonResult<string>(); JavaScriptSerializer serializer = new JavaScriptSerializer(); serializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoJsonConverter() }); result.Status = false; result.StatusMessage = "未知错误"; string response = string.Empty; string logisticsInterface = string.Empty; string dataDigest = string.Empty; // 已在菜鸟平台配置json格式数据传输 using (WebClient webClient = new WebClient()) { NameValueCollection postValues = Init(); dynamic user = new ExpandoObject(); user.employee_no = userCode; // 调用删除 logisticsInterface = serializer.Serialize(user); dataDigest = CaiNiaoApiUtilities.SignSdkRequest(logisticsInterface, secretKey); // 根据员工工号删除用户信息 postValues.Add("employee_no", userCode); postValues.Add("msg_type", "CNUSER_GET_LOGIN_TOKEN"); postValues.Add("data_digest", dataDigest); postValues.Add("logistics_interface", logisticsInterface); byte[] responseArray = webClient.UploadValues(url, postValues); response = Encoding.UTF8.GetString(responseArray); // 根据返回值判断 dynamic obj = serializer.Deserialize<ExpandoObject>(response); // 逻辑判断 if (IsPropertyExist(obj, "success") && obj.success == "true") { result.Status = true; result.ResultValue = obj.login_token; result.Data = response; result.StatusMessage = "成功返回"; } else { result.Status = false; result.Data = response; result.StatusMessage = "调用失败"; } } return result; }
/// <summary> /// 签名 /// </summary> /// <param name="content"></param> /// <param name="secretKey"></param> /// <returns></returns> public static string SignSdkRequest(string content, string secretKey) { byte[] binaryData = Encoding.UTF8.GetBytes(content + secretKey); MD5 md5 = new MD5CryptoServiceProvider(); byte[] output = md5.ComputeHash(binaryData); string dataDigest = Convert.ToBase64String(output); return dataDigest; }
/// <summary> /// 初始化 /// </summary> /// <returns></returns> private static NameValueCollection Init() { NameValueCollection postValues = new NameValueCollection(); postValues.Add("logistic_provider_id", logisticProviderId); postValues.Add("to_code", ""); return postValues; }
java版本的签名方法
String logisticsInterface = JSONArray.toJSONString(userMap); String dataSign = logisticsInterface + secretKey; byte[] binaryData=dataSign.getBytes("UTF-8"); byte[] signatureData = DigestUtils.md5Digest(binaryData); String dataDigest = Base64.encodeBase64String(signatureData);