本模块支持两种消息推送方式:
Webhook 方式(无需 access token)
开放平台 API 方式(需要 access token)
飞书的自定义机器人 Webhook 只能推送到群组,如果需要直接推送到个人聊天,就需要使用飞书开放平台 API,这需要:
本模块实现了完整的 token 管理机制:
Token 保存在 Store 表的 config 字段中,格式如下:
{
"feishu": {
"accessToken": "t-xxx",
"expireTime": 1709971200000
}
}
accessToken: 飞书的 tenant_access_tokenexpireTime: 过期时间戳(毫秒),提前 5 分钟过期在应用详情页的"凭证与基础信息"中,可以看到:
重要提示:
在应用详情页的"权限管理"中,需要开通以下权限:
配置权限后,需要等待管理员审批(如果你是管理员,可以直接通过)。
在服务器上配置以下环境变量:
# Linux/Mac
export FEISHU_APP_ID="cli_xxx"
export FEISHU_APP_SECRET="your_app_secret"
# Windows (PowerShell)
$env:FEISHU_APP_ID="cli_xxx"
$env:FEISHU_APP_SECRET="your_app_secret"
# Windows (CMD)
set FEISHU_APP_ID=cli_xxx
set FEISHU_APP_SECRET=your_app_secret
或者在 .env 文件中配置(如果项目使用 dotenv):
FEISHU_APP_ID=cli_xxx
FEISHU_APP_SECRET=your_app_secret
启动服务后,调用任意需要 access token 的接口,系统会自动:
如果配置错误,会返回错误信息:
{
"success": false,
"error": "飞书配置无效:请设置 FEISHU_APP_ID 和 FEISHU_APP_SECRET 环境变量",
"timestamp": "2026-03-09T14:00:00.000Z"
}
1. 前端请求接口
↓
2. 后端检查数据库中的 token
↓
3. 判断是否过期
├─ 未过期:直接使用
└─ 已过期:
├─ 调用飞书 API 获取新 token
├─ 保存到数据库
└─ 使用新 token
↓
4. 调用飞书 API 发送消息
↓
5. 返回结果
如果需要手动刷新 token(例如,怀疑 token 失效),可以:
或者,可以添加一个管理接口来手动刷新 token(需要自行实现)。
保护 App Secret
限制应用权限
监控 Token 使用
定期轮换密钥
可能原因:
解决方法:
是的,本模块会自动检查 token 是否过期,如果过期会自动刷新。
不建议。本模块已经实现了完整的 token 管理机制,手动指定 token 可能导致:
不用担心,下次请求时会自动重新获取并保存。
可以直接查询 Parse Server 的 Store 表:
const query = new Parse.Query('Store');
query.equalTo('objectId', 'config');
const store = await query.first({ useMasterKey: true });
const config = store.get('config');
console.log(config.feishu);
本模块使用单例模式实现了 TokenManager 类,负责:
配置管理模块从环境变量读取 app_id 和 app_secret:
export function getFeishuConfig(): FeishuConfig {
return {
app_id: process.env.FEISHU_APP_ID || '',
app_secret: process.env.FEISHU_APP_SECRET || ''
};
}
在路由中使用 token:
import { getTokenManager } from './token-manager';
// 获取 token
const tokenManager = getTokenManager();
const accessToken = await tokenManager.getAccessToken();
// 使用 token 调用飞书 API
const response = await fetch('https://open.feishu.cn/open-apis/im/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`
},
body: JSON.stringify({...})
});