- 入门指南
- 最佳实践
- 租户
- 操作
- 文件夹上下文
- 自动化
- 流程
- 作业
- 触发器
- 日志
- 监控
- 队列
- 资产
- 存储桶
- Orchestrator 测试
- 操作目录
- 配置文件
- 系统管理员
- 身份服务器
- 身份验证
- 其他配置
- 集成
- 传统机器人
- 故障排除
Webhook 用于在整个应用程序生态系统中更出色地集成 UiPath 自动化。您可以订阅 Orchestrator 事件并将其发送到任何外部 DCM、BPM 或 CRM 解决方案,同时通知不同的用户存在可供处理的新队列项目、触发器失败或已更新流程等事项。
Webhooks allow external systems to subscribe and listen to different types of Orchestrator events. The Webhooks page enables you to easily set them up, as well as view the ones that have been previously created. You can also disable webhooks, search for a specific one, edit or delete them.
Events are available for jobs, robots, queues, queue items, processes, and triggers. For the full list of event types and a few examples, please check this page.
每个事件都会向指定的 URL 发送包含信息的有效负载。一些属性是所有事件的通用属性,而另一些属性则特定于每种事件类型。
通用有效负载属性
| 属性名称 | 属性类型 | 说明和示例 |
|---|---|---|
| 类型 | 字符串 | 触发通知的事件类型。 对于所有类型的事件,都会显示此属性。 示例: "Type": "job.created""Type":"process.updated" |
| 活动 ID | 字符串 | 发生时为每个事件生成的唯一标识符。 对于所有类型的事件,都会显示此属性。 示例: "EventId":"3e5af0113e674ae597c579cb35ed8630" |
| 时间戳 | RFC 8601 日期 | 生成事件的日期和时间。 对于所有类型的事件,都会显示此属性。 示例: "Timestamp":"2018-11-02T11:47:48.5790797Z" |
| 租户 ID | 整数 | 在其中生成事件的租户的 ID。默认租户为 1。 对于所有类型的事件,都会显示此属性。 示例: "TenantId":3 |
| 用户 ID | 整数 | 操作触发事件的用户 ID。 如果事件是由机器人或触发器触发的,则不会显示此参数。 对于所有类型的事件,都会显示此属性。 示例: "UserId": 4947 |
| 文件夹 ID | 整数 | 生成事件的文件夹的 ID。 对于由新式机器人触发的事件,不会显示此参数。 示例: "FolderId": 26 |
权限
要在“Webhook”页面上执行各种操作,需要获得对 Webhook 的相应权限:
- View - Enables you to view webhooks and their details, as well as retrieve them using the API, send a ping request, or get the list of all the events to which a webhook can subscribe.
- “创建”- 此权限使您可以添加新的 Webhook。请注意,您还需要“查看”权限。
- Edit - Grants you the right to edit webhooks from the UI or by using the API. Please note that you also require View permissions.
- “删除”- 此权限使您可以删除 Webhook。请注意,您还需要“查看”权限。
身份验证
所有 Webhook HTTP 请求都使用您在创建 Webhook 时添加的密码进行身份验证。它通过 HMAC-SHA256 键控哈希与请求正文结合在一起。这将产生一个不包含任何密码信息的安全签名,该签名对于每个请求都是唯一的,并通过 X-UiPath-Signature HTTP 标头发送。
接收 Orchestrator 请求的客户端应用程序必须检查请求的真实性。请求签名遵循以下模式:
- 客户端应用程序收到 Orchestrator 发出的 Webhook 请求;
- 客户端应用程序根据请求计算签名;
- 客户端应用程序尝试将其计算的签名与请求签名进行匹配:
- 如果签名不匹配,则客户端应用程序不应处理请求。
- 如果签名匹配,则客户端应用程序应处理请求。
签名计算应按以下步骤完成:
-
检索
X-UiPath-SignatureHTTP 标头。 -
要获取原始签名字节,请从 Base64 解码标头的值。
-
检索原始请求正文。
备注:Orchestrator 请求始终使用 UTF-8 编码。
-
使用 SHA256 和签名密钥(UTF-8 编码)计算哈希值。
-
将计算得出的签名与
X-UiPath-SignatureHTTP 标头中的值进行比较:- 如果签名不匹配,则不会处理请求。
- 如果签名匹配,则客户端应用程序应处理请求。
签名验证示例
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public async Task<bool> IsValidRequestAsync(HttpRequestMessage request, string secret)
{
if (!request.Headers.TryGetValues("X-UiPath-Signature", out var headerValues))
return false;
var orchestratorSignature = Convert.FromBase64String(headerValues.First());
using (var sha = new HMACSHA256(key: Encoding.UTF8.GetBytes(secret)))
{
var computedSignature = sha.ComputeHash(await request.Content.ReadAsByteArrayAsync());
return ByteArrayEquals(orchestratorSignature, computedSignature);
}
}
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
public async Task<bool> IsValidRequestAsync(HttpRequestMessage request, string secret)
{
if (!request.Headers.TryGetValues("X-UiPath-Signature", out var headerValues))
return false;
var orchestratorSignature = Convert.FromBase64String(headerValues.First());
using (var sha = new HMACSHA256(key: Encoding.UTF8.GetBytes(secret)))
{
var computedSignature = sha.ComputeHash(await request.Content.ReadAsByteArrayAsync());
return ByteArrayEquals(orchestratorSignature, computedSignature);
}
}
const { createServer } = require('http');
const { createHmac } = require('crypto');
const PORT = 9090
const WEBHOOK_SECRET = '<same secret as configured in Orchestrator>'
const isValidRequest = (body /* Buffer */, secret /* string */, expectedSignature /* string */) =>
expectedSignature == null || createHmac('sha256', secret)
.update(body)
.digest('base64') === expectedSignature
const server = createServer((req, resp) => {
let body = new Buffer([])
req.on('data', chunk => body = Buffer.concat([body, chunk]))
req.on('end', () => {
if (!isValidRequest(body, WEBHOOK_SECRET, req.headers['x-uipath-signature'])) {
console.error('Invalid signature')
resp.statusCode = 401 // Unauthorized
} else {
let payload = JSON.parse(body.toString('utf8'))
// Process request
console.log(payload)
resp.statusCode = 202 // Accepted
}
resp.end()
})
})
server.listen(PORT)
const { createServer } = require('http');
const { createHmac } = require('crypto');
const PORT = 9090
const WEBHOOK_SECRET = '<same secret as configured in Orchestrator>'
const isValidRequest = (body /* Buffer */, secret /* string */, expectedSignature /* string */) =>
expectedSignature == null || createHmac('sha256', secret)
.update(body)
.digest('base64') === expectedSignature
const server = createServer((req, resp) => {
let body = new Buffer([])
req.on('data', chunk => body = Buffer.concat([body, chunk]))
req.on('end', () => {
if (!isValidRequest(body, WEBHOOK_SECRET, req.headers['x-uipath-signature'])) {
console.error('Invalid signature')
resp.statusCode = 401 // Unauthorized
} else {
let payload = JSON.parse(body.toString('utf8'))
// Process request
console.log(payload)
resp.statusCode = 202 // Accepted
}
resp.end()
})
})
server.listen(PORT)