# 事件订阅
# 知音楼会向应用推送订阅的事件,例如isv应用的授权、suite_ticket、会议录制知等。通过订阅这些事件,可以更好地与知音楼集成。你只需告知音楼当某个事件发生时,知音楼需要推送消息到哪个URL,知音楼会以HTTP POST请求的方式将事件内容以JSON格式推送给你。
# 使用场景
- 在会议中开启了会议录制,会议结束后想要获取到录制文件,此时就可以订阅会议录制事件,订阅后,当会议结束,就会收到来自知音楼的会议录制推送
上面只是其中一个案例,用户可以根据自己的需求选择性订阅对应事件 事件列表
# 事件订阅流程
目前只能通过人工手动配置接口回调地址和encrypt密钥,配置地址和订阅事件后,应用就可以接收到对应的事件推送
# 接收并响应事件
- 为了保证事件数据的安全性,所有事件推送数据均为加密后的数据,业务方收到数据后需要对数据内容进行解密方可使用,
- 推送数据以post请求,请求体为json的方式发送到应用设定的回调地址(回调地址后和encrypt密钥同时设置)
- 回调接口在3000ms内响应http状态码为200且响应报文为如下报文内容认为服务商应用已正常接收回调,否则认为是失败的
{
"code": 200
}
- 事件推送的数据结构
{
"event_id":"c6b8b25e-e983-4db6-a75a-3c9dd97914ef",//事件ID
"timestamp":1670335546,//时间戳
"encrypt":"ae337f99c4dbec3ddc98bfd196af822a",//加密的消息内容
}
encrypt解密后的数据结构请参考 事件列表
# 关于事件失败重试
- 在第一次推送失败后依次按照 60s、10m、30m、2h重试,共计四次重试,如果四次还不成功则丢弃该事件,不再重试
# 关于事件来源验证
- 事件推送时会在请求头增加 X-Request-Timestamp、X-Request-Nonce、X-Signature三个字段,将X-Request-Timestamp、X-Request-Nonce、encrypt密钥 拼接后按照 encode('utf-8') 编码得到 byte[] b1,再拼接上请求的原始 body, 得到一个 byte[] param。将 param 用 sha256 加密,得到字符串 sign, 校验 sign 是否和请求头 X-Signature 一致。
签名计算示例(php)
<?php
$encrypt_key = ""; // 开放平台后台的 Encrypt Key
$timestamp = "";
$nonce = "";
$body = ""; // 指整个请求体,不要在反序列化后再计算
$signature = hash("sha256", $timestamp . $nonce . $encrypt_key . $body);
签名计算示例(java)
using System.Security.Cryptography;
public static string calculateSignature(string timestamp, string nonce, string encryptKey, string body) {
StringBuilder content = new StringBuilder();
content.Append(timestamp);
content.Append(nonce);
content.Append(encryptKey);
content.Append(body);
SHA256 sha256 = new SHA256CryptoServiceProvider();
byte[] bytes_out = sha256.ComputeHash(Encoding.Default.GetBytes(content.ToString()));
string result = BitConverter.ToString(bytes_out);
result = result.Replace("-", "");
return result;
}
签名计算示例(golang)
import (
"crypto/sha256"
"fmt"
)
func calculateSignature(timestamp, nonce, encryptKey, bodystring string) string {
var b strings.Builder
b.WriteString(timestamp)
b.WriteString(nonce)
b.WriteString(encryptKey)
b.WriteString(bodystring) //bodystring 指整个请求体,不要在反序列化后再计算
bs := []byte(b.String())
h := sha256.New()
h.Write(bs)
bs = h.Sum(nil)
sig := fmt.Sprintf("%x", bs)
return sig
}
签名计算示例(python3)
import hashlib
bytes_b1 = (timestamp + nonce + encrypt_key).encode('utf-8')
bytes_b = bytes_b1 + body
h = hashlib.sha256(bytes_b)
signature = h.hexdigest()
签名计算示例(Node.js)
var crypto = require('crypto');
function calculateSignature(timestamp, nonce, encryptKey, body) {
const content = timestamp + nonce + encryptKey + body
const sign = crypto.createHash('sha256').update(content).digest('hex');
return sign
}
# 关于事件内容解密
- 使用app_secret/suite_secret作为密钥,使用AES-256-ECB算法来解密
消息解密计算示例(golang)
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"errors"
)
func AESDecryptString(input, aesKey string) (string, error) {
if keyString == "" {
return "", nil
}
originalData, err := base64.StdEncoding.DecodeString(keyString)
if err != nil {
return "", err
}
block, err := aes.NewCipher([]byte(aesKey)])
if err != nil {
logx.Errorf("Decrypt key error: % x", key)
return nil, err
}
decrypter := NewECBDecrypter(block)
decrypted := make([]byte, len(originalData))
decrypter.CryptBlocks(decrypted, originalData)
return pkcs5Unpadding(decrypted, decrypter.BlockSize()),nil
}