最近在跟菜鳥天地系統對接,業務中涉及到單點接入,感覺其實現思想很不錯,現分享一下,供大家參考:
從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);