1.前言
分享一個的我最近完成的開放平台設計
2.簡介
開放平台(以下簡API) 是為供應商和分銷商(以下簡稱開發人員)開放的API 接口,開發人員可以通過調用搜物API接口,快速的實現和搜物網的數據交換。搜物API支持Json 格式和XML數據格式進行數據交換,搜物API 根據你傳入的數據格式返回對應的數據,如你傳入的是是XML搜物API將返回Xml 格式數據如是Json 則返回Json格式數據
3.總體架構
如上圖所示,這里采用了分層來的思想開發本系統
l HelperLogic 助手類
l CahceLogic 緩存部分靜態數據,
l DataLogic 數據庫業務層
l OrderLogic 訂單邏輯層
l ProductLogic 產品邏輯層
l purviewLogic 鑒權邏輯層
l LogisticsLogic 物流模板邏輯層
4.業務邏輯處理
5.簽名算法
- 把請求中的參數 除了Signature 外 按照參數名稱進行正向排序
- 把所有參數名和參數值串在一起(不能有空格)
- 把后台設置的key值串接到“第二步”得到的字符串尾部(不能有空格)
- 采用MD5算法對“第三步”得到的字符串進行加密,生成Signature的值
/// <summary> /// 獲取簽名字符串 /// </summary> /// <param name="parameters">所有字符型的請求參數</param> /// <param name="secret">簽名密鑰(即搜物APIKey)</param> /// <returns>簽名</returns> public static string GetSignatureStr(IDictionary<string, string> parameters, string secret) { parameters.Remove("Signature"); // 第一步:把字典按Key的字母順序排序 IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters); IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator(); // 第二步:把所有參數名和參數值串在一起 StringBuilder query = new StringBuilder(); while (dem.MoveNext()) { string key = dem.Current.Key; string value = dem.Current.Value; if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value)) { query.Append(key + "=" + value + "&"); } } query.Append("key=" + secret); // 第三步:使用MD5加密 MD5 md5 = MD5.Create(); byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(query.ToString())); // 第四步:把二進制轉化為大寫的十六進制 StringBuilder result = new StringBuilder(); for (int i = 0; i < bytes.Length; i++) { string hex = bytes[i].ToString("X"); if (hex.Length == 1) { result.Append("0"); } result.Append(hex); } return result.ToString(); }
6.安全性考慮
1.權限接口控制
2.異常訪問
1.在30分鍾內,10次簽名出錯,認為賬號異常
2.訪問過於頻繁
3.手動添加黑名單
3.用戶可追溯性
我們主要實現2點功能 1. 記錄用戶的訪問操作,比如訪問那些接口,上傳了那些數據, 2.對於重要的數據的可追溯性,如商品價格,庫存等 3. 記錄每個請求耗時多久 為了實現以上3點功能,我們在這里引入log4net 做為日志系統,減少開發工作量
7.POST 數據和返回數據格式參考
[XmlRoot(ElementName = "DataPost")] public class DataPostCommon { /// <summary> /// 方法名 /// </summary> [XmlElement(ElementName = "MethodsName")] public string MethodsName { get; set; } /// <summary> /// ApiGuid /// </summary> [XmlElement(ElementName = "ApiGuid")] public string ApiGuid { get; set; } /// <summary> /// 數據簽名 /// </summary> [XmlElement(ElementName = "Signature")] public string Signature { get; set; } } [XmlRoot(ElementName = "DataPost")] /// <summary> /// 用戶Post 數據格式 /// </summary> public class DataPost<T> : DataPostCommon { [XmlElement(ElementName = "Parameters")] public T Parameters { get; set; } }
/// <summary> /// 服務返回 /// </summary> [XmlRoot(ElementName = "SeverReturn")] public class SeverReturn<T> { public SeverReturn() { ErrNo = ErrorNo.IsSuccess; } /// <summary> /// 錯誤代碼 /// </summary> [XmlElement(ElementName = "ErrNo")] public int ErrNo { get; set; } /// <summary> /// 錯誤描述 /// </summary> [XmlElement(ElementName = "ErrorDesc")] public string ErrorDesc { get; set; } [XmlElement(ElementName = "RunResults")] public T RunResults { get; set; } } }