此项目源码我也是站在巨人的肩膀上进行一个二次应用,感谢这位大神的共享
附上源码链接Feishu-Event-Subscribe: 【实验】飞书的事件订阅 主要是通讯录发生变动-比如新增、编辑员工-将会将事件信息发送到指定的API接口。 (gitee.com)
主要是通讯录发生变动-比如新增、编辑员工-将会将事件信息发送到指定的API接口。
飞书可以自己在pc客户端上创建一个自己的测试企业,用于开发调试。
进入**开发者后台**,在开发者后台的应用列表中,点击需要配置应用,进入应用详情页。
在应用详情页中,点击左侧面板中 事件订阅 菜单。之后的配置均在该菜单页面下页面!
可选:配置 Encrypt Key ,可以不配,配的话就需要对飞书的消息进行解密了(是对每条飞书推送过来的事件都要进行解密),解密后得到的才是正确的json格式。解密代码样例(这个是飞书官方提供的):
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class NotifyDataDecrypter {
private byte[] key;
/**
* @param encryptKey 飞书应用配置的 Encrypt Key
*/
public NotifyDataDecrypter(String encryptKey) {
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
// won't happen
}
key = digest.digest(encryptKey.getBytes(StandardCharsets.UTF_8));
}
/**
* 解密
* @param encrypt 请求json encrypt的对应的值
*/
public String decrypt(String encrypt)
throws InvalidAlgorithmParameterException,
InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException,
NoSuchPaddingException,
NoSuchAlgorithmException {
byte[] decode = Base64.getDecoder().decode(encrypt);
Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
byte[] iv = new byte[16];
System.arraycopy(decode, 0, iv, 0, 16);
byte[] data = new byte[decode.length - 16];
System.arraycopy(decode, 16, data, 0, data.length);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
byte[] r = cipher.doFinal(data);
if (r.length > 0) {
int p = r.length - 1;
for (; p >= 0 && r[p] <= 16; p--) {
}
if (p != r.length - 1) {
byte[] rr = new byte[p + 1];
System.arraycopy(r, 0, rr, 0, p + 1);
r = rr;
}
}
return new String(r, StandardCharsets.UTF_8);
}
}
设置Encrypt Key收到的请求消息体Json统一的格式都是,需要解密后才能使用:
// 收到的请求
{
"encrypt": "ds3da3sj32421lkkld4s5ao" // 加密字符串
}
配置 请求网址URL,就是说,后续飞书会将事件推送至改URL上,URL要求如下:
当在应用后台配置该 请求网址URL 的时候,飞书回向该URL发送一个POST请求进行URL校验,只有这个URL做出正确响应才能保存成功。URL校验会根据你是否配置了Encrypt Key发送不同的消息体Json。
未设置Encrypt Key发送的就是明文的Json:
// 收到的请求
{
"challenge": "ajls384kdjx98XX", // 应用需要原样返回的值
"token": "xxxxxx", // Token的使用可参考文档“通过Token验证事件来源”
"type": "url_verification" // 表示这是一个验证请求
}
设置Encrypt Key发送的就是加密的,解密之后的格式就是上面未设置Encrypt Key的明文Json格式:
// 实际收到的请求
{
"encrypt": "ds3da3sj32421lkkld4s5ao" // 加密字符串
}
// 解密后
{
"challenge": "ajls384kdjx98XX", // 应用需要原样返回的值
"token": "xxxxxx", // Token的使用可参考文档“通过Token验证事件来源”
"type": "url_verification" // 表示这是一个验证请求
}
不管加密还是没加密,URL校验都要求用户服务器在1s内向飞书返回如下格式:
//响应内容如下
{
"challenge": "ajls384kdjx98XX" // 应用需要原样返回的值
}
请求网址配置成功后,在下方你能看到可以订阅的事件列表,通过是否订阅的开关来 订阅 / 取消订阅事件。你想要什么类型的事件就在这里加什么事件,增加、取消后要进入 版本管理与发布重新进行应用的发布,让你订阅 / 取消的事件生效。
飞书通过HTTP POST发送Json格式时间数据到用户服务器中。用户服务器需要在1s内以HTTP 200状态码相应该请求(不需要返回什么Json数据什么的),否则视为此次事件推送失败,并以5s、5m、1h、6h的间隔重新推送事件,最多重试4次。
目前响应事件的数据格式有2个版本,现在新接入的事件都是采用2.0版本的格式。1.0版本就是返回一个用户Id给你然后你还要拿着用户Id在请求一次飞书接口;2.0版本就是直接把改动实体数据一次性全给你了,无需二次调用飞书接口。
事件返回包含schema字段,则是2.0版本;
如果接入了两个版本,会收到两种不同版本的事件!!!!!
// 2.0 版本示例
{
"schema": "2.0", // 事件格式的版本。无此字段的即为1.0
"header": {
"event_id": "f7984f25108f8137722bb63cee927e66", // 事件的唯一标识
"token": "066zT6pS4QCbgj5Do145GfDbbagCHGgF", // 即Verification Token
"create_time": "1603977298000000", // 事件发送的时间
"event_type": "contact.user_group.created_v3", // 事件类型
"tenant_key": "xxxxxxx", // 企业标识
"app_id": "cli_xxxxxxxx", // 应用ID
},
"event":{
... // 不同事件此处数据不同
}
}
// 1.0 版本示例
{
"ts": "1502199207.7171419", // 事件发送的时间,一般近似于事件发生的时间。
"uuid": "bc447199585340d1f3728d26b1c0297a", // 事件的唯一标识
"token": "41a9425ea7df4536a7623e38fa321bae", // 即Verification Token
"type": "event_callback", // event_callback-事件推送,url_verification-url地址验证
"event":{
... // 不同事件此处数据不同
}
}
飞书见按照事件发生的顺序推送,对于相关数据的不同事件,将由开放平台保证推送顺序,只有前一个接收响应成功才会推送下一个消息。
问:假如上一个事件相应飞书失败,且飞书重试4次(最多4次)之后均失败,后面的事件难道就卡住不动了?
不会,重复推送直至失效就会推送下一个了。
事件安全校验是「可选」的,可以针对收到的http请求进行检验,以确认其合法性。
参考代码
import org.apache.commons.codec.binary.Hex;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class FeishuSignatureUtils {
/**
* https://open.feishu.cn/document/ukTMukTMukTM/uYDNxYjL2QTM24iN0EjN/event-security-verification
*
* @param timestamp Http请求头中的X-Lark-Request-Timestamp
* @param nonce Http请求头中的X-Lark-Request-Nonce
* @param encryptKey 飞书应用后台自己配置的encrypt key
* @param bodyString 事件请求json串
*/
public static String calculateSignature(String timestamp,
String nonce,
String encryptKey,
String bodyString) throws NoSuchAlgorithmException {
StringBuilder content = new StringBuilder();
content.append(timestamp).append(nonce).append(encryptKey).append(bodyString);
MessageDigest alg = MessageDigest.getInstance("SHA-256");
return Hex.encodeHexString(alg.digest(content.toString().getBytes()));
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。