发送webhook到飞书机器人

ops/2024/12/22 0:44:01/

发送webhook到飞书机器人

参考链接 自定义机器人使用指南

创建自定义机器人

  1. 邀请自定义机器人进群。

    • 进入目标群组,在群组右上角点击更多按钮,并点击 设置。
      在这里插入图片描述

    • 在右侧 设置 界面,点击 群机器人
      在这里插入图片描述

    • 在 群机器人 界面点击 添加机器人

      在 添加机器人 对话框,找到并点击 自定义机器人
      在这里插入图片描述

    • 设置自定义机器人的头像、名称与描述,并点击 添加。
      在这里插入图片描述

  2. 获取自定义机器人的 webhook 地址
    机器人对应的 webhook 地址 格式如下:
    https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxxx
    请妥善保存好此 webhook 地址,不要公布在 Gitlab、博客等可公开查阅的网站上,避免地址泄露后被恶意调用发送垃圾消息。
    在这里插入图片描述

  3. 获取签名校验
    在 安全设置 区域,选择 签名校验。

选择签名校验后,系统已默认提供了一个秘钥。你也可以点击 重置,更换秘钥。
在这里插入图片描述

使用java发送http post到自定义机器人

  1. 计算签名校验,参考官方文档的SignDemo.java,自定义一个签名函数
    private static String genSign(String secret, long timestamp) throws NoSuchAlgorithmException, InvalidKeyException {//把timestamp+"\n"+密钥当做签名字符串String stringToSign = timestamp + "\n" + secret;//使用HmacSHA256算法计算签名Mac mac = Mac.getInstance("HmacSHA256");mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));byte[] signData = mac.doFinal(new byte[]{});return new String(Base64.encodeBase64(signData));}
  1. 计算时间戳
    需要注意的是,时间戳是以秒为单位的,并且要配置时区,不可直接使用System.currentTimeMillis()/1000来计算秒值
long seconds = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
  1. 创建富文本消息
    参考官方文档 发送富文本消息
    • 创建一个content对象
    private static JSONObject createOuterContent(String title, String message, String detail, String startTime, String endTime) {JSONObject result = new JSONObject();result.put("post", createPostJsonObject(title, message, detail, startTime, endTime));return result;}private static JSONObject createPostJsonObject(String title, String message, String detail, String startTime, String endTime) {JSONObject result = new JSONObject();result.put("zh_cn", createZhCNJsonObject(title, message, detail, startTime, endTime));return result;}private static JSONObject createZhCNJsonObject(String title, String message, String detail, String startTime, String endTime) {JSONObject result = new JSONObject();result.put("title", title);result.put("content", createContentList(message, detail, startTime, endTime));return result;}private static JSONArray createContentList(String message, String detail, String startTime, String endTime) {JSONArray result = new JSONArray();JSONArray item1 = new JSONArray();item1.add(createInnerHeadContent("message"));item1.add(createInnerTextContent(message));result.add(item1);JSONArray item2 = new JSONArray();item2.add(createInnerHeadContent("detail"));item2.add(createInnerTextContent(detail));result.add(item2);JSONArray item3 = new JSONArray();item3.add(createInnerHeadContent("startTime"));item3.add(createInnerTextContent(startTime));result.add(item3);JSONArray item4 = new JSONArray();item4.add(createInnerHeadContent("endTime"));item4.add(createInnerTextContent(endTime));result.add(item4);return result;}private static JSONObject createInnerHeadContent(String tag) {JSONObject result = new JSONObject();result.put("tag", "text");result.put("text", tag+": ");return result;}private static JSONObject createInnerTextContent(String text) {JSONObject result = new JSONObject();result.put("tag", "text");result.put("text", text);return result;}
  • 再创建完整的json对象

完整代码如下

java版本

public class FeishuWebhook {private static final Logger logger = LoggerFactory.getLogger(FeishuWebhook.class);public static final String DEFAULT_DATETIME_FORMATTER_STR = "yyyy-MM-dd HH:mm:ss";public static final DateTimeFormatter DEFAULT_DATETIME_FORMATTER =DateTimeFormatter.ofPattern(DEFAULT_DATETIME_FORMATTER_STR);public static void send(String url, String secret, AlertDO alertDO) {logger.info("FeishuWebhook.send, url:{}, alertDO={}", url, alertDO);JSONObject requestBody = createRequestBody(secret, alertDO);logger.info("requestBody:{}", requestBody);JSONObject result = HttpUtils.postForJsonObject(url, null, null, requestBody);logger.info("result:{}", result);}private static String genSign(String secret, long timestamp) throws NoSuchAlgorithmException, InvalidKeyException {//把timestamp+"\n"+密钥当做签名字符串String stringToSign = timestamp + "\n" + secret;//使用HmacSHA256算法计算签名Mac mac = Mac.getInstance("HmacSHA256");mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));byte[] signData = mac.doFinal(new byte[]{});return new String(Base64.encodeBase64(signData));}private static JSONObject createRequestBody(String secret, AlertDO alertDO) {JSONObject requestBody = new JSONObject();long seconds = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();logger.info("seconds:{}", seconds);
//        int seconds = 1734515343;try {String sign = genSign(secret, seconds);requestBody.put("timestamp", seconds);requestBody.put("sign", sign);requestBody.put("msg_type", "post");String title = "通知";String message = alertDO.getMessage();String detail = alertDO.getDetail();String startTime = DEFAULT_DATETIME_FORMATTER.format(LocalDateTime.ofInstant(alertDO.getStartTime().toInstant(), ZoneId.systemDefault()));String endTime = DEFAULT_DATETIME_FORMATTER.format(LocalDateTime.ofInstant(alertDO.getEndTime().toInstant(), ZoneId.systemDefault()));requestBody.put("content", createOuterContent(title, message, detail, startTime, endTime));} catch (Exception e) {e.printStackTrace();}return requestBody;}private static JSONObject createOuterContent(String title, String message, String detail, String startTime, String endTime) {JSONObject result = new JSONObject();result.put("post", createPostJsonObject(title, message, detail, startTime, endTime));return result;}private static JSONObject createPostJsonObject(String title, String message, String detail, String startTime, String endTime) {JSONObject result = new JSONObject();result.put("zh_cn", createZhCNJsonObject(title, message, detail, startTime, endTime));return result;}private static JSONObject createZhCNJsonObject(String title, String message, String detail, String startTime, String endTime) {JSONObject result = new JSONObject();result.put("title", title);result.put("content", createContentList(message, detail, startTime, endTime));return result;}private static JSONArray createContentList(String message, String detail, String startTime, String endTime) {JSONArray result = new JSONArray();JSONArray item1 = new JSONArray();item1.add(createInnerHeadContent("message"));item1.add(createInnerTextContent(message));result.add(item1);JSONArray item2 = new JSONArray();item2.add(createInnerHeadContent("detail"));item2.add(createInnerTextContent(detail));result.add(item2);JSONArray item3 = new JSONArray();item3.add(createInnerHeadContent("startTime"));item3.add(createInnerTextContent(startTime));result.add(item3);JSONArray item4 = new JSONArray();item4.add(createInnerHeadContent("endTime"));item4.add(createInnerTextContent(endTime));result.add(item4);return result;}private static JSONObject createInnerHeadContent(String tag) {JSONObject result = new JSONObject();result.put("tag", "text");result.put("text", tag+": ");return result;}private static JSONObject createInnerTextContent(String text) {JSONObject result = new JSONObject();result.put("tag", "text");result.put("text", text);return result;}}

python版本
FeishuBotHypertextWithSecret.py

import base64
import hashlib
import hmac
from datetime import datetimeimport requestsWEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/xx"
WEBHOOK_SECRET = "ssssssss"class LarkBot:def __init__(self, secret: str) -> None:if not secret:raise ValueError("invalid secret key")self.secret = secretdef gen_sign(self, timestamp: int) -> str:string_to_sign = '{}\n{}'.format(timestamp, self.secret)hmac_code = hmac.new(string_to_sign.encode("utf-8"), digestmod=hashlib.sha256).digest()sign = base64.b64encode(hmac_code).decode('utf-8')return signdef send(self) -> None:timestamp = int(datetime.now().timestamp())sign = self.gen_sign(timestamp)params = {"timestamp": timestamp,"sign": sign,"msg_type": "post","content": {"post": {"zh_cn": {"title": "项目更新通知","content": [[{"tag": "text","text": "项目有更新: "}, {"tag": "a","text": "请查看","href": "http://www.example.com/"}, {"tag": "at","user_id": "ou_18eac8********17ad4f02e8bbbb"}]]}}}}resp = requests.post(url=WEBHOOK_URL, json=params)resp.raise_for_status()result = resp.json()if result.get("code") and result["code"] != 0:print(result["msg"])returnprint("消息发送成功")def main():bot = LarkBot(secret=WEBHOOK_SECRET)bot.send()if __name__ == '__main__':main()

LarkBotWithoutSecret.py

from datetime import datetimeimport requestsWEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/sss"class LarkBot:def send(self, content: str) -> None:timestamp = int(datetime.now().timestamp())params = {"timestamp": timestamp,"msg_type": "text","content": {"text": content},}resp = requests.post(url=WEBHOOK_URL, json=params)resp.raise_for_status()result = resp.json()if result.get("code") and result["code"] != 0:print(result["msg"])returnprint("消息发送成功")def main():bot = LarkBot()bot.send(content="我是一只高级鸽子!")if __name__ == '__main__':main()

http://www.ppmy.cn/ops/143892.html

相关文章

数据结构_双向循环链表实战

双向循环链表实战 package XHLB;public class SXXHLB {// 定义双向链表节点static class DoubleListNode { //Node(节点)private int val;private DoubleListNode prev;private DoubleListNode next;public DoubleListNode(int val) {this.val val;this.next null;this.prev …

webpack打包流程及原理

Webpack 是一个模块打包工具,它可以分析项目的依赖关系,将这些依赖转换和打包为合适的格式以供浏览器使用。以下是 Webpack 打包流程的简化版: **初始化:**读取 webpack 配置文件,创建 compiler 对象。 **配置&#x…

学习笔记:Verilog连续赋值及在线仿真

参考 https://www.runoob.com/w3cnote/verilog-assign.htmlassign, 全加器 连续赋值语句是 Verilog 数据流建模的基本语句,用于对 wire 型变量进行赋值 assign LHS_target RHS_expression ; LHS(left hand side) 指赋…

使用Python实现无人机自动导航系统:探索智能飞行的奥秘

友友们好! 我的新专栏《Python进阶》正式启动啦!这是一个专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。 在这个专栏中,你将会找到: ● 深入解析:每一篇文章都将…

【HTML】Shadow DOM

Shadow DOM 允许将隐藏的 DOM 树附加到常规的 DOM 树中。它以 shadow root 节点为起始根节点,在这个根节点的下方,可以是任意元素,和普通的 DOM 元素一样。这样,你就可以创建一个独立的 DOM 子树,它与主文档隔离开来&a…

服务器被入侵登录不上怎么办?

在数字化时代,服务器作为数据存储与业务运行的核心载体,其安全性直接关系到企业的生死存亡。然而,随着网络攻击手段的不断升级,服务器被入侵的事件屡见不鲜,导致系统瘫痪、数据泄露等严重后果。当您发现自己的服务器被…

python elasticsearch 8.x通过代理发起请求方法

由于python elasticsearch v8 engine的源码包中并未开放对于请求添加proxies的支持,导致在某些环境下无法连通外网的es服务。目前网上暂无相关的修改内容,我这边提供下自己修改的动态运行时替换elasticsearch包的源码方法demo import gzip import ssl i…

点击数字层级从 admin.vue 跳转到 inviter-list.vue 组件

文章目录 1、admin.vue2、inviter-list.vue 1、admin.vue 好的&#xff0c;我们来分析一下代码中“层级”这一列的逻辑&#xff0c;并探讨它与后端的关联。 “层级” 列的逻辑 在您的代码中&#xff0c;“层级”列的渲染逻辑如下&#xff1a; <el-table-columnalign&quo…