系列目录 [已更新最新开发文章, 点击查看详细]
在《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 服务器发送的回调请求参数.
- long fileId = context.Request.QueryString["fileId"].ToLong(); // 文件 ID
- string status = context.Request.QueryString["status"]; // 转换的结果
- string reason = context.Request.QueryString["reason"]; // 若转换失败, 则返回失败原因
- string thumbnail = context.Request.QueryString["thumbnail"]; // 缩略图地址
- string nonce = context.Request.QueryString["nonce"]; // 回调随机数
- string signature = context.Request.QueryString["signature"]; // BIMFACE 的加密签名
3, 根据请求参数计算签名.
签名的计算方式: MD5(``appKey:appSecret:compareId:status:nonce'')
- /// <summary>
- /// 根据回调的参数计算签名
- /// </summary>
- /// <param name="appKey"> 开发者秘钥 </param>
- /// <param name="appSecret"> 开发者密码 </param>
- /// <param name="fileId">BIMFace 发出的回调信息: 文件 ID</param>
- /// <param name="status">BIMFace 发出的回调信息: 转换的结果 </param>
- /// <param name="nonce">BIMFace 发出的回调信息: 回调随机数 </param>
- /// <returns></returns>
- public static string GetCallbackSignature(string appKey, string appSecret, long fileId, string status, string nonce)
- {
- return string.Format("{0}:{1}:{2}:{3}:{4}", appKey, appSecret, fileId, status, nonce).EncryptByMD5();
- }
其中使用到的扩展方法 EncryptByMD5() 实现如下:
- /// <summary>
- /// 自定义扩展方法: 使用 MD5(不可逆加密) 算法加密字符串. 返回二进制形式的字符串. 字符串的编码方式为 UTF8.
- /// </summary>
- /// <param name="this"> 扩展对象. 字符串. 编码方式为 UTF8</param>
- /// <param name="caseType"> 字符串大小写. 默认小写 </param>
- /// <returns></returns>
- public static string EncryptByMD5(this string @this, CaseType caseType = CaseType.Lower)
- {
- using (MD5 md5 = MD5.Create())
- {
- var sb = new StringBuilder();
- byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(@this));
- foreach (byte bytes in hashBytes)
- {
- sb.Append(bytes.ToString("X2"));//X2 表示二进制
- }
- return caseType == CaseType.Upper ? sb.ToString() : sb.ToString().ToLower();
- }
- }
- View Code
4, 验证签名.
将步骤 3 中的计算结果与 BIMFace 发出的回调消息签名做对比, 如果签名一直则证明该消息是安全可靠的.
- /// <summary>
- /// 验证 BIMFace 发出的回调消息签名信息是否安全可靠
- /// </summary>
- /// <param name="appKey"> 开发者秘钥 </param>
- /// <param name="appSecret"> 开发者密码 </param>
- /// <param name="fileId">BIMFace 发出的回调信息: 文件 ID</param>
- /// <param name="status">BIMFace 发出的回调信息: 转换的结果 </param>
- /// <param name="nonce">BIMFace 发出的回调信息: 回调随机数 </param>
- /// <param name="signature">BIMFace 发出的回调信息: 签名 </param>
- /// <param name="custCalcSignature"> 输出参数: 根据 BIMFACE 平台的加密规则计算出来的签名信息 </param>
- /// <returns></returns>
- public static bool CheckCallbackSignature(string appKey, string appSecret, long fileId, string status, string nonce, string signature, out string custCalcSignature)
- {
- /* signature(签名): 为了确保回调消息是由 BIMFace 发出的, 应用在收到回调消息后, 须验证签名.
- * 签名的计算方式: MD5("appKey:appSecret:fileId:status:nonce"), 如果应用计算的签名与 BIMFace 返回的签名一致, 则证明该消息是安全可靠的.
- */
- custCalcSignature = GetCallbackSignature(appKey, appSecret, fileId, status, nonce);
- return custCalcSignature == signature;
- }
5, 根据签名验证结果做出回执响应消息.
如果验证签名成功则可以将模型转换, 模型集成, 模型对比, 生成离线数据包等操作的处理结果写入数据库保存供后续其他业务逻辑使用.
签名成功后, 须向 BIMFace 发送回执, 回执消息: HTTP STATUS 200.
- bool checkSignature = CallbackUtils.CheckCallbackSignature(appKey, appSecret, fileId, status, nonce, signature, out custCalcSignature);
- if (checkSignature)
- {
- tip = "[BIMFace 发出的回调信息签名验证成功!]"
- + Environment.NewLine
- + callbackResponse;
- LogUtility.Info(tip);
- //Todo 此处可以根据 fileId 把相关的信息写入数据库中
- // 回执消息: 应用收到回调后, 须向 BIMFace 发送回执, 回执消息: HTTP STATUS 200
- context.Response.Write("HTTP STATUS 200");
- }
- else
- {
- tip = "[BIMFace 发出的回调信息签名验证不通过!]"
- + Environment.NewLine
- + callbackResponse
- + Environment.NewLine
- + "自定义计算签名 custCalcSignature:" + custCalcSignature;
- LogUtility.Error(tip);
- context.Response.Write(tip);
- }
如果签名验证失败, 则需要将签名信息写入文本日志供分析原因使用. 此时通过编码方式实现邮件, 短信, 微信消息等方式通知开发者回调程序处理结果不正确, 使其及时知道业务系统的运行状况.
6, 发布程序并使用该回调地址.
程序完成后发布到开发者服务器. 在模型转换, 模型集成, 模型对比, 生成离线数据包等操作的 API 接口参数中使用该回调地址.
完整的代码如下:
- /// <summary>
- /// BimFace 回调处理
- /// </summary>
- public class BimFaceHandler : IHttpHandler
- {
- public void ProcessRequest(HttpContext context)
- {
- context.Response.ContentType = "text/plain";
- context.Response.ContentEncoding = Encoding.UTF8;
- string appKey = ConfigUtility.GetAppSettingValue("BIMFACE_AppKey");
- string appSecret = ConfigUtility.GetAppSettingValue("BIMFACE_AppSecret");
- string uid = context.Request.QueryString["uid"]; // SparkBimFace
- #region 校验
- if (appKey.IsNullOrWhiteSpace())
- {
- LogUtility.Error("BIMFace appKey 配置项没有配置!");
- return;
- }
- if (appSecret.IsNullOrWhiteSpace())
- {
- LogUtility.Error("BIMFace appSecret 配置项没有配置!");
- return;
- }
- if (uid.IsNullOrWhiteSpace())
- {
- LogUtility.Error("[非法请求] 回调地址 Url 链接中的参数 uid 没有配置或者配置的值为空!");
- return;
- }
- #endregion
- long fileId = context.Request.QueryString["fileId"].ToLong(); // 文件 ID
- string status = context.Request.QueryString["status"]; // 转换的结果
- string reason = context.Request.QueryString["reason"]; // 若转换失败, 则返回失败原因
- string thumbnail = context.Request.QueryString["thumbnail"]; // 缩略图地址
- string nonce = context.Request.QueryString["nonce"]; // 回调随机数
- string signature = context.Request.QueryString["signature"]; // BIMFACE 的加密签名
- string callbackResponse = string.Format("fileId:{0},\r\nstatus:{1},\r\nreason:{2},\r\nthumbnail:{3},\r\nnonce:{4},\r\nsignature:{5}",
- fileId, status, reason, thumbnail, nonce, signature);
- string tip;
- string custCalcSignature;
- bool checkSignature = CallbackUtils.CheckCallbackSignature(appKey, appSecret, fileId, status, nonce, signature, out custCalcSignature);
- if (checkSignature)
- {
- tip = "[BIMFace 发出的回调信息签名验证成功!]"
- + Environment.NewLine
- + callbackResponse;
- LogUtility.Info(tip);
- //Todo 此处可以根据 fileId 把相关的信息写入数据库中
- // 回执消息: 应用收到回调后, 须向 BIMFace 发送回执, 回执消息: HTTP STATUS 200
- context.Response.Write("HTTP STATUS 200");
- }
- else
- {
- tip = "[BIMFace 发出的回调信息签名验证不通过!]"
- + Environment.NewLine
- + callbackResponse
- + Environment.NewLine
- + "自定义计算签名 custCalcSignature:" + custCalcSignature;
- LogUtility.Error(tip);
- context.Response.Write(tip);
- }
- context.Response.End();
- }
- /// <summary>
- /// 该属性获得一个布尔值, 指示另一个请求是否可以使用该 HTTP 处理程序的实例.
- /// <para > 如果设置为 true, 能提高性能, 但要注意线程之间安全性问题. 如果设置为 false, 则线程是安全的 </para>
- /// </summary>
- public bool IsReusable
- {
- get
- {
- return false;
- }
- }
- }
系列目录 [已更新最新开发文章, 点击查看详细]
来源: https://www.cnblogs.com/SavionZhang/p/12396058.html