@blocklet/payment-vendor
v1.22.30
Published
Payment Kit Vendor SDK - Signature verification, lifecycle management, and type definition integration solution
Readme
@blocklet/payment-vendor
Payment Kit 供应商集成软件开发工具包,为供应商提供标准化的认证、签名验证和安全通信解决方案。
概述
本 SDK 旨在简化供应商与 Payment Kit 的集成过程,提供标准化的接口和安全机制。主要解决供应商在接收、验证和处理来自中介请求时面临的技术挑战。
核心功能模块
🔐 认证与安全模块
- 签名验证:基于 Ed25519 算法的请求签名验证
- 白名单管理:中介访问控制和权限管理
- 时间戳验证:防重放攻击机制
🛡️ Express 中间件
- 认证中间件:自动验证请求合法性
- 日志中间件:记录请求和响应信息
- 错误处理中间件:统一的错误响应格式
- 限流中间件:防止接口滥用
- 健康检查中间件:系统状态监控
安装
npm install @blocklet/payment-vendor快速开始
本 SDK 支持两种使用场景,请根据你的角色选择对应的集成方式:
📋 角色对比
| 角色 | 身份 | 主要职责 | 使用的 SDK 功能 | 典型场景 | |------|------|----------|----------------|----------| | 🏪 Vendor(供应商) | 商品/服务提供方 | • 接收发货请求• 处理用户订单• 提供服务实例 | • 中间件验证• 白名单管理• 请求解析 | Blocklet 开发者、SaaS 服务商、API 提供商 | | 🔄 Broker(中介) | Payment Kit 等平台 | • 发送发货请求• 管理支付流程• 协调供应商 | • 请求签名• 认证生成• 通信协议 | Payment Kit、电商平台、分发平台 |
🏪 供应商端集成(Vendor Side)
适用场景: 你是商品/服务的提供方,需要接收并处理来自 Payment Kit 的发货请求。
核心能力:
- ✅ 请求验证:自动验证来自 Payment Kit 的签名请求
- ✅ 白名单管理:控制哪些中介可以访问你的服务
- ✅ 安全防护:防重放攻击、限流保护、错误处理
- ✅ 监控运维:健康检查、请求日志、系统状态
基础集成(5分钟快速上手)
import VendorSDK from '@blocklet/payment-vendor';
import express from 'express';
const app = express();
app.use(express.json());
// 1. 配置信任的中介白名单(Payment Kit 等)
VendorSDK.setBrokers([
{
id: 'payment-kit',
name: 'Payment Kit Service',
publicKey: process.env.PAYMENT_KIT_PUBLIC_KEY, // Payment Kit 提供给你的公钥
status: 'active',
rateLimit: 100 // 每分钟最多100次请求
}
]);
// 2. 应用安全中间件(自动验证所有请求)
app.use('/api/vendor', VendorSDK.middleware.ensureAuth());
// 3. 实现发货端点(这是你的核心业务逻辑)
app.post('/api/vendor/deliveries', async (req, res) => {
const { userInfo, deliveryParams, description } = req.body;
try {
// 你的发货逻辑:创建实例、分配资源、发送邮件等
const result = await createInstanceForUser(userInfo, deliveryParams);
res.json({
success: true,
status: 'completed',
message: '发货成功',
data: {
instanceId: result.instanceId,
serviceUrl: result.serviceUrl,
installUrl: result.installUrl
}
});
} catch (error) {
res.status(500).json({
success: false,
status: 'failed',
message: error.message
});
}
});
// 4. 健康检查端点(供 Payment Kit 监控)
app.get('/health', VendorSDK.middleware.healthCheck({
service: 'my-vendor-service',
version: '1.0.0'
}));
// 你的业务逻辑实现
async function createInstanceForUser(userInfo, deliveryParams) {
console.log(`为用户 ${userInfo.userDid} 创建实例: ${deliveryParams.instanceName}`);
// 这里实现你的具体业务逻辑
// 例如:调用云服务API、创建数据库记录、发送通知等
return {
instanceId: `inst_${Date.now()}`,
serviceUrl: `https://my-service.com/${deliveryParams.instanceName}`,
installUrl: `https://my-service.com/install/${deliveryParams.instanceName}`
};
}
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`🏪 供应商服务运行在端口 ${port}`);
});🔄 中介端集成(Broker Side - Payment Kit)
适用场景: 你是 Payment Kit 或其他中介服务,需要向供应商发送发货请求。
核心能力:
- ✅ 请求签名:使用 Ed25519 算法为发送给供应商的请求签名
- ✅ 安全通信:确保请求的完整性和来源可信性
- ✅ 协议标准化:统一的请求格式和响应处理
- ✅ 错误处理:完善的异常情况处理机制
基础发货请求
import { VendorAuth } from '@blocklet/payment-vendor';
// 1. 准备发货请求数据(符合 DeliveryRequest 接口)
const deliveryRequest = {
path: '/api/vendor/deliveries',
method: 'POST',
timestamp: Date.now(),
userInfo: {
userDid: 'z1muQ3xqHQK2uiACHyZ7G5S1scgbZiEdB',
email: '[email protected]',
description: '用户购买了 Blocklet 实例'
},
deliveryParams: {
instanceName: 'my-awesome-app',
productId: 'blocklet_001',
blockletMetaUrl: 'https://registry.blocklet.io/blocklets/my-app',
customParams: {
region: 'us-west-2',
tier: 'standard'
}
},
description: '为用户创建 Blocklet 实例'
};
// 2. 生成签名请求(推荐方式:使用 Header 签名)
const { headers, body } = VendorAuth.signRequestWithHeaders(
deliveryRequest,
);
// 3. 发送到供应商
const response = await fetch('https://vendor.example.com/api/vendor/deliveries', {
method: 'POST',
headers, // 自动包含 x-broker-vendor-sig 和 x-broker-did
body // JSON 字符串
});
const result = await response.json();
if (result.success) {
console.log('✅ 发货成功:', result.data);
// 保存 instanceId 和 serviceUrl 供后续使用
} else {
console.error('❌ 发货失败:', result.message);
}完整的中介服务示例
import { VendorAuth } from '@blocklet/payment-vendor';
import express from 'express';
const app = express();
app.use(express.json());
// 发货管理端点(Payment Kit 内部使用)
app.post('/api/internal/fulfill-order', async (req, res) => {
try {
const { orderId, userId, productId, vendorEndpoint } = req.body;
// 构建发货请求
const deliveryRequest = {
path: '/api/vendor/deliveries',
method: 'POST',
timestamp: Date.now(),
userInfo: {
userDid: userId,
email: req.body.userEmail,
description: `订单 ${orderId} 的发货请求`
},
deliveryParams: {
instanceName: `${productId}-${userId.slice(-8)}`,
productId,
customParams: req.body.customParams || {}
},
description: `处理订单 ${orderId} 的发货`
};
// 签名并发送请求
const { headers, body } = VendorAuth.signRequestWithHeaders(
deliveryRequest,
);
const vendorResponse = await fetch(`${vendorEndpoint}/api/vendor/deliveries`, {
method: 'POST',
headers,
body
});
const result = await vendorResponse.json();
// 返回处理结果
res.json({
orderId,
fulfilled: result.success,
vendorResponse: result,
timestamp: new Date().toISOString()
});
} catch (error: any) {
console.error('发货请求失败:', error);
res.status(500).json({
error: '发货处理失败',
message: error.message
});
}
});完整集成示例
🏪 供应商端完整示例
import VendorSDK from '@blocklet/payment-vendor';
import express from 'express';
const app = express();
// 基础中间件
app.use(express.json());
// 配置信任的中介白名单(动态配置)
VendorSDK.setBrokers(() => {
const configSource = process.env.VENDOR_DISTRIBUTORS || '[]';
return JSON.parse(configSource);
});
// 应用安全中间件
app.use('/api/vendor', VendorSDK.middleware.rateLimiter({
windowMs: 60000,
defaultLimit: 100
}));
app.use('/api/vendor', VendorSDK.middleware.ensureAuth({
skipTimestamp: false,
maxAge: 300000
}));
// 核心发货端点
app.post('/api/vendor/deliveries', async (req, res) => {
try {
const { userInfo, deliveryParams, description } = req.body;
// 处理发货逻辑
const result = await processFulfillment(userInfo, deliveryParams, description);
res.json({
success: result.success,
status: result.success ? 'completed' : 'failed',
data: result.data,
message: result.message
});
} catch (error) {
console.error('处理请求失败:', error);
res.status(500).json({
success: false,
error: '内部服务器错误',
message: error.message
});
}
});
// 管理接口:查看中介状态
app.get('/api/admin/brokers', async (req, res) => {
try {
const brokers = await VendorSDK.getWhitelist();
res.json({
total: brokers.length,
active: brokers.filter(d => d.status === 'active').length,
brokers: brokers.map(d => ({
id: d.id,
name: d.name,
status: d.status,
rateLimit: d.rateLimit
}))
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 错误处理中间件
app.use(VendorSDK.middleware.errorHandler);
// 业务逻辑函数(供应商实现)
async function processFulfillment(userInfo: any, deliveryParams: any, description: string) {
console.log(`处理发货请求 - 用户: ${userInfo.userDid}, 实例: ${deliveryParams.instanceName}`);
try {
// 你的具体业务逻辑:
// 1. 创建服务实例
// 2. 分配资源
// 3. 发送通知邮件
// 4. 更新数据库等
const instanceId = `inst_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
return {
success: true,
data: {
instanceId,
serviceUrl: `https://my-service.com/service/${deliveryParams.instanceName}`,
installUrl: `https://my-service.com/install/${instanceId}`,
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString()
},
message: '发货成功'
};
} catch (error: any) {
return {
success: false,
data: null,
message: `发货失败: ${error.message}`
};
}
}
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`🏪 供应商服务运行在端口 ${port}`);
});🔄 中介端完整示例
import { VendorAuth } from '@blocklet/payment-vendor';
import express from 'express';
const app = express();
app.use(express.json());
// Payment Kit 内部的发货管理服务
class VendorFulfillmentService {
private brokerSecretKey: string;
private brokerPublicKey: string;
constructor() {
this.brokerSecretKey = process.env.BROKER_SECRET_KEY!;
this.brokerPublicKey = process.env.BROKER_PUBLIC_KEY!;
}
// 向供应商发送发货请求
async fulfillOrder(orderData: {
orderId: string;
userId: string;
userEmail: string;
productId: string;
instanceName: string;
vendorEndpoint: string;
customParams?: Record<string, any>;
}) {
try {
// 构建标准化的发货请求
const deliveryRequest = {
path: '/api/vendor/deliveries',
method: 'POST',
timestamp: Date.now(),
userInfo: {
userDid: orderData.userId,
email: orderData.userEmail,
description: `订单 ${orderData.orderId} 的发货请求`
},
deliveryParams: {
instanceName: orderData.instanceName,
productId: orderData.productId,
customParams: orderData.customParams || {}
},
description: `处理订单 ${orderData.orderId} 的发货`
};
// 签名请求
const { headers, body } = VendorAuth.signRequestWithHeaders(
deliveryRequest,
);
// 发送到供应商
const response = await fetch(`${orderData.vendorEndpoint}/api/vendor/deliveries`, {
method: 'POST',
headers,
body,
timeout: 30000 // 30秒超时
});
if (!response.ok) {
throw new Error(`Vendor responded with status: ${response.status}`);
}
const result = await response.json();
return {
orderId: orderData.orderId,
fulfilled: result.success,
vendorResponse: result,
timestamp: new Date().toISOString()
};
} catch (error: any) {
console.error(`发货请求失败 - 订单: ${orderData.orderId}`, error);
throw new Error(`Vendor fulfillment failed: ${error.message}`);
}
}
// 查询发货状态
async checkFulfillmentStatus(instanceId: string, vendorEndpoint: string) {
try {
const statusRequest = {
path: '/api/vendor/status',
method: 'GET',
timestamp: Date.now(),
params: { instanceId }
};
const { headers, body } = VendorAuth.signRequestWithHeaders(
statusRequest,
);
const response = await fetch(`${vendorEndpoint}/api/vendor/status`, {
method: 'POST',
headers,
body
});
return await response.json();
} catch (error: any) {
throw new Error(`Status check failed: ${error.message}`);
}
}
}
// Payment Kit 使用示例
const fulfillmentService = new VendorFulfillmentService();
app.post('/api/internal/fulfill-order', async (req, res) => {
try {
const result = await fulfillmentService.fulfillOrder(req.body);
res.json(result);
} catch (error: any) {
res.status(500).json({
error: '发货处理失败',
message: error.message
});
}
});
app.listen(3000, () => {
console.log('🔄 Payment Kit 中介服务运行在端口 3000');
});🔄 快速对比:两种集成方式
| 对比项 | 🏪 供应商端 | 🔄 中介端 |
|--------|----------------|---------------|
| 主要用途 | 接收并处理发货请求 | 发送发货请求给供应商 |
| 核心导入 | import VendorSDK from '@blocklet/payment-vendor' | import { VendorAuth } from '@blocklet/payment-vendor' |
| 关键配置 | VendorSDK.setBrokers([...]) 设置信任的中介 | process.env.BROKER_SECRET_KEY 配置自己的私钥 |
| 核心功能 | 使用 middleware.ensureAuth() 验证请求 | 使用 VendorAuth.signRequestWithHeaders() 签名请求 |
| 请求方向 | 被动接收来自 Payment Kit 的请求 | 主动向供应商发送请求 |
| 典型端点 | POST /api/vendor/deliveries (接收) | 调用供应商的 /api/vendor/deliveries |
| 安全职责 | 验证请求签名,防止未授权访问 | 生成请求签名,证明身份合法 |
配置管理
中介配置
SDK 支持两种配置模式:
静态配置模式
适用于中介列表相对稳定的场景:
VendorSDK.setBrokers([
{
id: 'payment-kit',
name: 'Payment Kit Service',
publicKey: '0x680688a033b86da179f39018e074410439ae82a97c4cb8e1ad16c26eabcc1795',
status: 'active',
rateLimit: 100
}
]);动态配置模式
适用于需要实时更新中介配置的场景:
VendorSDK.setBrokers(() => {
// 从环境变量、配置文件或数据库读取
const configSource = process.env.VENDOR_DISTRIBUTORS || '[]';
const brokers = JSON.parse(configSource);
return brokers.map(item => ({
id: item.brokerId,
name: item.name,
publicKey: item.publicKey,
status: item.enabled ? 'active' : 'inactive',
rateLimit: item.rateLimit || 100
}));
});环境变量配置
# 中介配置
export VENDOR_DISTRIBUTORS='[{
"brokerId": "payment-kit",
"name": "Payment Kit Service",
"publicKey": "0x680688a033b86da179f39018e074410439ae82a97c4cb8e1ad16c26eabcc1795",
"enabled": true,
"rateLimit": 100
}]'
# Payment Kit 公钥(用于签名验证)
export PAYMENT_KIT_PUBLIC_KEY="0x680688a033b86da179f39018e074410439ae82a97c4cb8e1ad16c26eabcc1795"
# 服务端口
export PORT=3000API 文档
核心 API
VendorSDK.setBrokers(brokersOrGetter)
设置中介白名单配置。
参数:
brokersOrGetter:BrokerConfig[]|() => BrokerConfig[] | Promise<BrokerConfig[]>
BrokerConfig 接口:
| 字段 | 类型 | 必需 | 描述 |
|------|------|------|------|
| id | string | ✅ | 中介唯一标识符 |
| name | string | ✅ | 中介显示名称 |
| publicKey | string | ✅ | 用于验证签名的公钥 |
| status | 'active' | 'inactive' | ✅ | 中介状态,仅 active 状态可通过验证 |
| rateLimit | number | ❌ | 可选的请求频率限制 |
VendorSDK.getWhitelist()
返回当前配置的中介白名单。
返回: Promise<BrokerConfig[]>
中间件 API
VendorSDK.middleware.ensureAuth(options?)
Express 认证中间件,验证请求签名和中介权限。
可选参数:
skipTimestamp: boolean - 是否跳过时间戳验证maxAge: number - 时间戳最大有效期(毫秒)
// 基础用法
app.use('/api/vendor', VendorSDK.middleware.ensureAuth());
// 自定义配置
app.use('/api/vendor', VendorSDK.middleware.ensureAuth({
skipTimestamp: false,
maxAge: 300000 // 5分钟
}));VendorSDK.middleware.rateLimiter(options?)
请求频率限制中间件。
可选参数:
windowMs: number - 时间窗口(毫秒)defaultLimit: number - 默认最大请求次数skipSuccessfulRequests: boolean - 是否跳过成功请求计数
// 使用默认配置
app.use('/api/vendor', VendorSDK.middleware.rateLimiter());
// 自定义配置
app.use('/api/vendor', VendorSDK.middleware.rateLimiter({
windowMs: 60000, // 1分钟
defaultLimit: 100, // 默认最多100次请求
skipSuccessfulRequests: false
}));VendorSDK.middleware.healthCheck(options?)
健康检查中间件。
可选参数:
service: string - 服务名称version: string - 版本信息includeDetails: boolean - 是否包含详细系统信息
// 基础用法
app.get('/health', VendorSDK.middleware.healthCheck());
// 自定义配置
app.get('/health', VendorSDK.middleware.healthCheck({
service: 'launcher-vendor',
version: '1.0.0',
includeDetails: true
}));VendorSDK.middleware.errorHandler
统一错误处理中间件。
// 应该放在所有路由的最后
app.use(VendorSDK.middleware.errorHandler);签名相关 API
VendorAuth.signRequestWithHeaders(request)
生成包含签名头部的完整请求对象,适用于 header 签名验证场景。
参数:
request: Record<string, any> - 请求数据对象brokerSk: string - 中介私钥brokerDid: string - 中介公钥/DID
返回: { headers: Record<string, string>, body: string }
import { VendorAuth } from '@blocklet/payment-vendor';
const requestData = {
path: '/api/vendor/deliveries',
method: 'POST',
timestamp: Date.now(),
userInfo: {
userDid: 'user_did_123',
email: '[email protected]'
},
body: { appName: 'test-app' }
};
const { headers, body } = VendorAuth.signRequestWithHeaders(
requestData,
);
// 发送请求
const response = await fetch('https://vendor.example.com/api/deliveries', {
method: 'POST',
headers, // 包含 x-broker-vendor-sig 和 x-broker-vendor-did
body // JSON 字符串
});VendorAuth.signAndSerialize(data, secretKey)
签名并序列化请求数据,用于 body 签名验证场景。
参数:
data: VendorRequest - 请求数据对象secretKey: string - 请求方私钥
返回: string - 序列化的签名请求
const signedBody = VendorAuth.signAndSerialize(requestData, secretKey);
const response = await fetch('https://vendor.example.com/api/deliveries', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: signedBody
});错误处理
常见错误及解决方案
"Brokers must be an array"
原因: 传入 setBrokers 的参数类型不正确。
解决方案:
// ❌ 错误用法
VendorSDK.setBrokers(undefined);
VendorSDK.setBrokers("invalid");
// ✅ 正确用法
VendorSDK.setBrokers([]); // 空数组
VendorSDK.setBrokers([{
id: 'test',
name: 'Test',
publicKey: 'xxx',
status: 'active'
}]);
VendorSDK.setBrokers(() => parseConfigFromEnv()); // 函数"Missing signature header"
原因: 使用了不正确的签名方式。
解决方案:
// ❌ 错误用法(缺少签名头部)
const signedBody = VendorAuth.signAndSerialize(data, secretKey);
fetch(url, { body: signedBody });
// ✅ 正确用法(包含签名头部)
const { headers, body } = VendorAuth.signRequestWithHeaders(data);
fetch(url, { method: 'POST', headers, body });"Broker not in whitelist"
原因: 请求的中介不在白名单中或状态为 inactive。
解决方案:
- 检查中介 ID 是否正确
- 确认中介状态为 'active'
- 验证白名单配置是否正确加载
"Request timestamp too old"
原因: 请求时间戳过期(超过5分钟)。
解决方案:
// 确保时间戳是当前时间
const requestData = {
// ...其他字段
timestamp: Date.now() // 使用当前时间戳
};调试和监控
启用详细日志
// 添加请求日志中间件
app.use('/api/vendor', VendorSDK.middleware.ensureAuth());手动验证签名
import { VendorAuth } from '@blocklet/payment-vendor';
async function debugSignature(requestBody, expectedBrokerId) {
try {
const brokers = await VendorSDK.getWhitelist();
const broker = brokers.find(d => d.id === expectedBrokerId);
if (!broker) {
console.log('中介不存在:', expectedBrokerId);
return false;
}
const isValid = await VendorAuth.verifyRequest(requestBody, broker);
console.log('签名验证结果:', isValid);
return isValid;
} catch (error) {
console.error('签名验证失败:', error);
return false;
}
}监控端点
// 健康检查
app.get('/health', VendorSDK.middleware.healthCheck());
// 中介状态查询
app.get('/api/admin/brokers', async (req, res) => {
try {
const brokers = await VendorSDK.getWhitelist();
res.json({
total: brokers.length,
active: brokers.filter(d => d.status === 'active').length,
brokers: brokers.map(d => ({
id: d.id,
name: d.name,
status: d.status,
rateLimit: d.rateLimit
}))
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// 系统信息
app.get('/api/admin/info', (req, res) => {
res.json({
version: require('../package.json').version,
uptime: process.uptime(),
memory: process.memoryUsage(),
nodeVersion: process.version
});
});最佳实践
生产环境配置
使用环境变量管理敏感信息
export PAYMENT_KIT_PUBLIC_KEY="your_public_key_here" export VENDOR_DISTRIBUTORS='[...]'配置适当的限流和超时设置
app.use('/api/vendor', VendorSDK.middleware.rateLimiter({ windowMs: 60000, max: 1000 // 根据实际需要调整 }));定期轮换密钥和证书
- 建议每季度更新一次密钥对
- 使用配置热重载功能平滑切换
安全建议
验证所有入站请求的签名
app.use('/api/vendor', VendorSDK.middleware.ensureAuth());使用 HTTPS 传输敏感数据
// 强制 HTTPS app.use((req, res, next) => { if (req.header('x-forwarded-proto') !== 'https') { res.redirect(`https://${req.header('host')}${req.url}`); } else { next(); } });实施适当的错误处理
app.use(VendorSDK.middleware.errorHandler);定期审查和更新中介列表
- 使用动态配置模式便于管理
- 定期检查并移除不活跃的中介
性能优化
- 使用缓存减少重复计算
- 合理设置限流参数
- 定期清理日志文件
- 监控内存使用情况
示例代码
完整的集成示例请参考 examples/usage-example.ts 文件。
技术支持
如需技术支持或报告问题,请访问项目的 GitHub 仓库提交 Issue。
许可证
本项目采用 Apache-2.0 许可证。详细信息请参阅 LICENSE 文件。
