C#開發BIMFACE系列36 服務端API之:回調機制

  在《C# 開發 BIMFACE 系列文章》中介紹了模型轉換、模型對比介面。這2個功能介面比較特殊,發起請求後,邏輯處理是在BIMFACE雲端進行的,通常需要5~10分鐘。當邏輯處理完成後,BIMFACE通過回調機制通知對比結果。

  BIMFACE支援回調機制。在調用方發起模型轉換、模型集成、模型對比、生成離線數據包等操作時,可以通過傳入參數callback的方式來啟用回調機制。 在BIMFACE處理完相應操作後,根據調用方傳入的回調地址通知調用方相應操作的結果。

URL參數:

signature(簽名):為了確保回調消息是由BIMFACE發出的,調用方在收到回調消息後,須驗證簽名。簽名的計算方式:MD5(``appKey:appSecret:compareId:status:nonce''),如果調用方計算的簽名與BIMFACE返回的簽名一致,則證明該消息是安全可靠的。

應用收到回調後,須向BIMFace發送回執,回執消息:HTTP STATUS 200

Callbak示例:

* 調用方對文件1685236328506848發起了模型轉換,並且傳入的回調地址是:https://my.app.com/callback。    * BIMFACE在模型轉換任務處理完成後,會發送一個get請求到調用方的callback地址:   https://my.app.com/callback?fileId=1685236328506848&status=success&thumbnail=38044a282f55cb26e3704643dccd2b55/thumbnail/96.png,38044a282f55cb26e3704643dccd2b55/thumbnail/256.png&reason=&signature=99a6fccb1894dfdb4cce48fd5ec58110&nonce=123abc    * 調用方接收到這條請求後,可以進行signature的驗證,並發送回執消息。

特別說明

  BIMFACE的回調機制與微信公眾號或者小程式開發類似,需要開發者提供開發者伺服器,且有正式合法域名或者外網IP,對外公布一個地址,BIMFACE伺服器能訪問到該地址才可以。

  如果無法提供有效的回調地址,則只能通過手動調用 模型轉換、模型集成、模型對比、生成離線數據包等操作的其他API來獲取對應的處理結果。

  在.NET平台下實現該功能可以使用 WebService、一般處理程式、WebAPI等技術方式實現。下面介紹在一般處理程式中實現的思路與步驟。

 1、配置BIMACE開發者帳號資訊。

  在web.config 或者 app.config 文件中配置開發者帳號資訊,供驗證消息簽名時使用。

 2、獲取BIMFace伺服器發送的回調請求參數。

1 long fileId = context.Request.QueryString["fileId"].ToLong();  // 文件ID  2 string status = context.Request.QueryString["status"];         // 轉換的結果  3 string reason = context.Request.QueryString["reason"];         // 若轉換失敗,則返回失敗原因  4 string thumbnail = context.Request.QueryString["thumbnail"];   // 縮略圖地址  5 string nonce = context.Request.QueryString["nonce"];           // 回調隨機數  6 string signature = context.Request.QueryString["signature"];   // BIMFACE的加密簽名

 3、根據請求參數計算簽名。

  簽名的計算方式:MD5(``appKey:appSecret:compareId:status:nonce'')

 1 /// <summary>   2 ///  根據回調的參數計算簽名   3 /// </summary>   4 /// <param name="appKey">開發者秘鑰</param>   5 /// <param name="appSecret">開發者密碼</param>   6 /// <param name="fileId">BIMFace發出的回調資訊:文件ID</param>   7 /// <param name="status">BIMFace發出的回調資訊:轉換的結果</param>   8 /// <param name="nonce">BIMFace發出的回調資訊:回調隨機數</param>   9 /// <returns></returns>  10 public static string GetCallbackSignature(string appKey, string appSecret, long fileId, string status, string nonce)  11 {  12     return string.Format("{0}:{1}:{2}:{3}:{4}", appKey, appSecret, fileId, status, nonce).EncryptByMD5();  13 }

 其中使用到的擴展方法 EncryptByMD5() 實現如下:

 1 /// <summary>   2 ///  自定義擴展方法:使用 MD5(不可逆加密) 演算法加密字元串。返回二進位形式的字元串。字元串的編碼方式為UTF8。   3 /// </summary>   4 /// <param name="this">擴展對象。字元串。編碼方式為UTF8</param>   5 /// <param name="caseType">字元串大小寫。默認小寫</param>   6 /// <returns></returns>   7 public static string EncryptByMD5(this string @this, CaseType caseType = CaseType.Lower)   8 {   9     using (MD5 md5 = MD5.Create())  10     {  11         var sb = new StringBuilder();  12         byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(@this));  13         foreach (byte bytes in hashBytes)  14         {  15             sb.Append(bytes.ToString("X2"));//X2 表示二進位  16         }  17  18         return caseType == CaseType.Upper ? sb.ToString() : sb.ToString().ToLower();  19     }  20 }
View Code

 4、驗證簽名。

  將步驟3中的計算結果與BIMFace發出的回調消息簽名做對比,如果簽名一直則證明該消息是安全可靠的。 

 1 /// <summary>   2 ///  驗證BIMFace發出的回調消息簽名資訊是否安全可靠   3 /// </summary>   4 /// <param name="appKey">開發者秘鑰</param>   5 /// <param name="appSecret">開發者密碼</param>   6 /// <param name="fileId">BIMFace發出的回調資訊:文件ID</param>   7 /// <param name="status">BIMFace發出的回調資訊:轉換的結果</param>   8 /// <param name="nonce">BIMFace發出的回調資訊:回調隨機數</param>   9 /// <param name="signature">BIMFace發出的回調資訊:簽名</param>  10 /// <param name="custCalcSignature">輸出參數:根據BIMFACE平台的加密規則計算出來的簽名資訊</param>  11 /// <returns></returns>  12 public static bool CheckCallbackSignature(string appKey, string appSecret, long fileId, string status, string nonce, string signature, out string custCalcSignature)  13 {  14     /* signature(簽名):為了確保回調消息是由BIMFace發出的,應用在收到回調消息後,須驗證簽名。  15     * 簽名的計算方式:MD5("appKey:appSecret:fileId:status:nonce"),如果應用計算的簽名與BIMFace返回的簽名一致,則證明該消息是安全可靠的。  16     */  17     custCalcSignature = GetCallbackSignature(appKey, appSecret, fileId, status, nonce);  18  19     return custCalcSignature == signature;  20 }

 5、根據簽名驗證結果做出回執響應消息。

      如果驗證簽名成功則可以將模型轉換、模型集成、模型對比、生成離線數據包等操作的處理結果寫入資料庫保存供後續其他業務邏輯使用。

   簽名成功後,須向BIMFace發送回執,回執消息:HTTP STATUS 200。

 1 bool checkSignature = CallbackUtils.CheckCallbackSignature(appKey, appSecret, fileId, status, nonce, signature, out custCalcSignature);   2 if (checkSignature)   3 {   4     tip = "[BIMFace發出的回調資訊簽名驗證成功!]"   5           + Environment.NewLine   6           + callbackResponse;   7     LogUtility.Info(tip);   8   9     //Todo 此處可以根據fileId把相關的資訊寫入資料庫中  10  11     // 回執消息:應用收到回調後,須向BIMFace發送回執,回執消息:HTTP STATUS 200  12     context.Response.Write("HTTP STATUS 200");  13 }  14 else  15 {  16     tip = "[BIMFace發出的回調資訊簽名驗證不通過!]"  17         + Environment.NewLine  18         + callbackResponse  19         + Environment.NewLine  20         + "自定義計算簽名 custCalcSignature:" + custCalcSignature;  21  22     LogUtility.Error(tip);  23  24     context.Response.Write(tip);  25 }

如果簽名驗證失敗,則需要將簽名資訊寫入文本日誌供分析原因使用。此時通過編碼方式實現郵件、簡訊、微信消息等方式通知開發者回調程式處理結果不正確,使其及時知道業務系統的運行狀況。

 6、發布程式並使用該回調地址。

  程式完成後發布到開發者伺服器。在模型轉換、模型集成、模型對比、生成離線數據包等操作的API介面參數中使用該回調地址。

完整的程式碼如下:

 1 /// <summary>   2 ///  BimFace回調處理   3 /// </summary>   4 public class BimFaceHandler : IHttpHandler   5 {   6     public void ProcessRequest(HttpContext context)   7     {   8         context.Response.ContentType = "text/plain";   9         context.Response.ContentEncoding = Encoding.UTF8;  10  11         string appKey = ConfigUtility.GetAppSettingValue("BIMFACE_AppKey");  12         string appSecret = ConfigUtility.GetAppSettingValue("BIMFACE_AppSecret");  13         string uid = context.Request.QueryString["uid"];  // SparkBimFace  14  15         #region 校驗  16         if (appKey.IsNullOrWhiteSpace())  17         {  18             LogUtility.Error("BIMFace appKey 配置項沒有配置!");  19  20             return;  21         }  22  23         if (appSecret.IsNullOrWhiteSpace())  24         {  25             LogUtility.Error("BIMFace appSecret 配置項沒有配置!");  26  27             return;  28         }  29  30         if (uid.IsNullOrWhiteSpace())  31         {  32             LogUtility.Error("[非法請求]回調地址Url鏈接中的參數 uid 沒有配置或者配置的值為空!");  33  34             return;  35         }  36         #endregion  37  38         long fileId = context.Request.QueryString["fileId"].ToLong();  // 文件ID  39         string status = context.Request.QueryString["status"];         // 轉換的結果  40         string reason = context.Request.QueryString["reason"];         // 若轉換失敗,則返回失敗原因  41         string thumbnail = context.Request.QueryString["thumbnail"];   // 縮略圖地址  42         string nonce = context.Request.QueryString["nonce"];           // 回調隨機數  43         string signature = context.Request.QueryString["signature"];   // BIMFACE的加密簽名  44  45         string callbackResponse = string.Format("fileId:{0},rnstatus:{1},rnreason:{2},rnthumbnail:{3},rnnonce:{4},rnsignature:{5}",  46                                                  fileId, status, reason, thumbnail, nonce, signature);  47         string tip;  48         string custCalcSignature;  49  50         bool checkSignature = CallbackUtils.CheckCallbackSignature(appKey, appSecret, fileId, status, nonce, signature, out custCalcSignature);  51         if (checkSignature)  52         {  53             tip = "[BIMFace發出的回調資訊簽名驗證成功!]"  54                   + Environment.NewLine  55                   + callbackResponse;  56             LogUtility.Info(tip);  57  58             //Todo 此處可以根據fileId把相關的資訊寫入資料庫中  59  60             // 回執消息:應用收到回調後,須向BIMFace發送回執,回執消息:HTTP STATUS 200  61             context.Response.Write("HTTP STATUS 200");  62         }  63         else  64         {  65             tip = "[BIMFace發出的回調資訊簽名驗證不通過!]"  66                 + Environment.NewLine  67                 + callbackResponse  68                 + Environment.NewLine  69                 + "自定義計算簽名 custCalcSignature:" + custCalcSignature;  70  71             LogUtility.Error(tip);  72  73             context.Response.Write(tip);  74         }  75  76         context.Response.End();  77     }  78  79     /// <summary>  80     ///  該屬性獲得一個布爾值,指示另一個請求是否可以使用該HTTP處理程式的實例。  81     /// <para>如果設置為true,能提高性能,但要注意執行緒之間安全性問題。如果設置為false,則執行緒是安全的</para>  82     /// </summary>  83     public bool IsReusable  84     {  85         get  86         {  87             return false;  88         }  89     }  90 }

Tags: