# Kintone License Server 一个 Node.js TypeScript 服务端程序,用于验证客户端的许可证,通过 RSA 签名生成 JWT。 ## 功能 - 提供 `POST /api/license/check` 接口,根据请求 body 中的 `domain`、`pluginId`、`pluginKey` 参数: - 如果许可证不存在,创建 30 天试用许可证(到期时间为最后一天的 23:59:59)。 - 如果存在,加载现有许可证。 - 使用对应的插件 RSA 私钥生成 JWT,返回给客户端。 - JWT payload 结构符合客户端要求的 LicenseInfo 接口。 - 支持试用和付费许可证:基于数据库 `purchase_date` 是否有值判断 `isPaid`,付费许可证 `expiredTime = -1`。 ## 运行步骤 ### 本地开发 1. **安装依赖:** ``` npm install ``` 2. **构建项目:** ``` npm run build ``` 3. **初始化数据库:** - 运行初始化脚本:`init-db.sql` 4. **启动服务器:** ``` npm run dev # 开发模式 npm start # 生产模式(需预先构建) ``` ### Docker Compose 部署(推荐) 1. **启动所有服务:** ``` docker-compose up --build -d ``` 这将启动: - PostgreSQL 数据库(在 `db` 服务中) - 许可证服务器应用(在 `app` 服务中,端口 3000) 2. **检查服务状态:** ``` docker-compose ps ``` 3. **查看日志:** ``` docker-compose logs -f ``` 4. **停止服务:** ``` docker-compose down ``` 5. **测试 API:** - 健康检查:`GET http://localhost:3000/health` - 许可证检查:`POST http://localhost:3000/api/license/check` 请求 body 示例: ```json { "domain": "example.com", "pluginId": "test-plugin", "pluginKey": "default-plugin" } ``` 成功响应: ```json { "success": true, "jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` ## 项目结构 - `src/server.ts`:主服务器代码,包含 Express 应用、路由和数据库连接。 - `init-db.sql`:数据库初始化脚本,创建 plugins、customers、licenses 三张表。 - `private/kintone-vue-template/rsa_private.pem`:示例 RSA 私钥(已导入数据库)。 ## 数据库结构 - **plugins**:插件信息(id, plugin_id, plugin_name, private_key, deleted)。多插件支持,每个插件有唯一私钥。 - **customers**:客户信息(id, name, email, phone, comment)。暂未使用。 - **licenses**:许可证记录(id, domain, plugin_id, expired_time, purchase_date, plugin_fk, customer_fk, message)。 - 外键 `plugin_fk` 关联插件,`customer_fk` 关联客户(暂未实施)。 许可逻辑: - 请求 (domain, pluginId) 组合唯一标识许可证。 - 试用:`purchase_date = NULL`,`isPaid = false`,`expiredTime` = 30 天后时间戳。 - 付费:`purchase_date` 被外部系统设置,`isPaid = true`,`expiredTime = -1`。 ## 认证和安全性 - 使用 RSA-256 签名 JWT,私钥存储在 `plugins` 表中,按 `pluginKey` 区分。 - 默认插入 "default-plugin" 插件,使用现有 RSA 私钥。 - 数据库连接硬编码凭据(生产环境使用环境变量,如 .env 文件)。 ## 注意事项 - 当前实现试用许可证,30 天过期时间硬编码。 - 付费购买由其他系统更新 `purchase_date`,本服务仅校验。 - PostgreSQL 需要预先配置和运行。 - 代码使用 TypeScript 严格模式,确保类型安全。