# SslPlatform **Repository Path**: wuccloud/ssl-platform ## Basic Information - **Project Name**: SslPlatform - **Description**: SSL证书申请+自动续期 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-26 - **Last Updated**: 2026-09-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SSL 证书管理平台 本仓库包含两套**可独立运行**的程序: | 程序 | 目录 | 干什么 | 谁用 | | --- | --- | --- | --- | | **平台后端 API**(含 Web 界面) | `backend/src/SslPlatform.Api` | 证书申请/续期/部署、租户与用户管理、DNS 凭证、任务调度、平台授权校验 | 交付给客户,部署在客户的服务器上 | | **授权签发工具** | `backend/tools/SslPlatform.LicenseIssuer.Web` | 生成签名密钥、签发 `.lic` 授权文件、查看签发台账 | **只**在平台方自己本机使用,绝不交付 | 两者通过 `.lic` 授权文件发生业务联系,代码上**没有任何引用关系**。 > 本文件是全仓库总览。改动代码前的强制约束(红线、中文注释规范、前端打包要求、密钥保管规则)见 [`AGENTS.md`](./AGENTS.md),冲突时以 `AGENTS.md` 为准。 --- ## 一、我该看哪份文档 | 你要做的事 | 看这份 | | --- | --- | | 在本机跑起平台、建账号、导入授权、查接口、部署上线 | [`backend/src/SslPlatform.Api/README.md`](backend/src/SslPlatform.Api/README.md) | | 生成密钥、签发授权给客户、查台账、备份密钥 | [`backend/tools/SslPlatform.LicenseIssuer.Web/README.md`](backend/tools/SslPlatform.LicenseIssuer.Web/README.md) | | 从零给一个客户开通(跨两个工程) | 本文件[第三节](#三端到端第一次给客户开通) | | 改代码 | [`AGENTS.md`](./AGENTS.md) | 两份工程 README 都带「界面导览」一节并配了界面截图(平台侧在 `backend/src/SslPlatform.Api/docs/images/`,签发侧在 `backend/tools/SslPlatform.LicenseIssuer.Web/docs/images/`),想看界面长什么样直接翻图即可。 --- ## 二、组成与关系 ``` frontend/ (Vue 3 + Vite 的 SPA,构建产物同步进 Api 的 wwwroot) │ npm run deploy ▼ backend/src/SslPlatform.Api/wwwroot ←── 单端口 http://localhost:5000 同时提供接口与页面 │ │ 引用 ▼ backend/src/SslPlatform.Licensing ←── 授权契约库:授权文件模型、公钥表、验签器、北京时间原语 ▲ │ 引用 │ backend/tools/SslPlatform.LicenseIssuer.Web →── 签发工具:含私钥与签发能力,本机专用 ``` 三条必须理解的设计: - **只有签发工具持有私钥**。平台后端只做「验签 + 落库」,不含签发能力——若把签发逻辑编进交付物,客户反编译即可自签一份「无限额度、永久有效」的授权,整套机制当场失效。 - **验签公钥硬编码**在 `SslPlatform.Licensing/LicensePublicKeys.cs`,不可通过配置替换(可替换的信任根等于没有信任根),代价是「换签名密钥要重新编译」。 - `SslPlatform.Licensing` 会随平台交付物一起分发,这是刻意设计(公钥本就必须硬编码在服务端),不是违规。 --- ## 三、端到端:第一次给客户开通 ``` ① 生成密钥 ② 登记公钥并发布 ③ 签发授权 ④ 导入平台 ⑤ 核对 签发工具 服务端源码 + 客户环境 签发工具 平台地址或 CLI 平台界面 / CLI ``` 1. **生成密钥**:启动签发工具 →「密钥与目录」页 → 选 `prod` 用途 → 填 keyId → 生成。 产出 `<密钥根目录>\prod\.private.key`,页面同时给出一段**公钥代码行**。 2. **登记公钥并重新发布**(最容易被漏掉的一步): 把公钥代码行粘进 `backend/src/SslPlatform.Licensing/LicensePublicKeys.cs` → 重新构建发布,并**更新到客户环境**。 ⚠️ 两步都完成之前,用这把密钥签发的授权会被客户平台**拒绝导入**(验签时 keyId 查不到公钥)。 📌 签发工具页面上提示的路径与此处一致(曾因授权契约抽库而指向 `SslPlatform.Api/Services/Licensing/...` 这个旧位置,已于 2026-09-26 修正)。 3. **签发授权**:签发工具 →「签发授权」页 → 选 `prod` 密钥 → 填被授权方与额度 → 签发。 产出 `<密钥根目录>\prod\issued\<授权编号>.lic`,并记入台账。 `dev` 用途签发的授权**仅供自测,不得交付客户**。 4. **导入平台**(二选一): - 界面:「平台设置 → 平台授权 → 导入」; - 命令行: ```powershell cd backend/src/SslPlatform.Api dotnet run -- license-import --file <授权文件路径> --dry-run # 先看判定结果 dotnet run -- license-import --file <授权文件路径> # 确认无误再正式导入 ``` 导入成功后立即生效、无需重启,系统从「只读」变为「可用」。 5. **核对**:`dotnet run -- license-status` 或界面查看状态;客户侧在「平台设置 → 平台授权」页核对授权编号与到期时间。 后续维护: - **续期 / 换一份**:重新签发(可用新编号),客户直接导入即**覆盖**旧件,**无需先卸载**。 - **误导入要撤销**: ```powershell cd backend/src/SslPlatform.Api dotnet run -- license-remove --export ./license-backup.lic # 先备份,看清后果 dotnet run -- license-remove --confirm # 真要卸载再加 --confirm ``` 授权原文只存在于数据库、平台不保留原文件,卸载后系统内不再有副本(见平台 README 第四节)。 --- ## 四、环境准备 | 项 | 要求 | | --- | --- | | .NET SDK | 10(工程目标框架为 `net10.0`) | | Node.js / npm | 需要,仅用于构建平台前端 | | 数据库 | 默认 SQLite,**无需单独安装**;可换成 PostgreSQL / MySQL / SQL Server | | 终端 | 本文命令按 Windows PowerShell 写 | --- ## 五、生产部署检查清单 平台侧(详见[平台 README](backend/src/SslPlatform.Api/README.md#八生产部署检查清单)): - [ ] 注入 `SSL_PLATFORM_MASTER_KEY`、`SSL_PLATFORM_JWT_KEY`(缺失会**拒绝启动**)。 - [ ] 确认 `appsettings*.json` 里 `Security:MasterKey` / `JwtKey` 为空(配置文件优先,填了会让环境变量被静默忽略)。 - [ ] 首个高权限账号:临时 `SeedDemoData=true` + 注入两个初始密码环境变量 → 启动一次 → 改回 `false` 重启;或用 `create-account`。 - [ ] **交付构建移除开发用途公钥**:`LicensePublicKeys.cs` 只保留 `Production-2026`。 - [ ] `App__PublicBaseUrl=https://<对外域名>`(否则一键部署命令「执行成功但证书不更新」)。 - [ ] 授权若绑定主机名,用 `License__Host` 指定稳定名称(容器随机主机名会导致「没过期却只读」)。 - [ ] 数据库目录不要放在云同步目录或网络盘。 签发侧: - [ ] 签发工具**不部署**到客户环境或公网服务器,不进任何发布包 / 镜像 / 部署脚本。 - [ ] 备份两处:工程内 `App_Data/issuer.db` + 密钥目录(`H:\ssl-platform-keys` 的 `*.private.key` 与 `issued\`)。 - [ ] 不要为了省事把工程目录压给别人:`issuer.db` 内含明文私钥种子,等同签发权凭证。 --- ## 六、最容易踩的三个坑 | 现象 | 原因 | | --- | --- | | 「数据不见了」 | 2026-09-26 **之前**平台用相对路径 SQLite(相对**进程工作目录**),换个目录启动就换了库;现落点已固定到「数据根」(见平台 README 第二节)。若仍对不上,多为此前旧版本在别处留下的 `App_Data\`,或设过 `SSLPLATFORM_DATA_ROOT`。 | | 「改了前端页面没变化」 | 没执行 `npm run deploy`(后端托管 `wwwroot`,只改源码不影响 5000 端口),或需强刷 Ctrl + F5。 | | 「签发工具读不到密钥 / 授权导入被拒」 | 前者是 `SSLPLATFORM_KEY_HOME` 没在**启动时的环境块**里生效;后者是公钥没登记进服务端源码并重新发布(见[第三节](#三端到端第一次给客户开通))。 | --- ## 七、仓库结构 ``` licenses/ ├─ AGENTS.md 改动代码前的强制约束(权威) ├─ README.md 本文件 ├─ backend/ │ ├─ SslPlatform.slnx 解决方案(**不含**签发工具) │ ├─ src/ │ │ ├─ SslPlatform.Api/ 平台后端(含 README、docs/images/ 界面截图、托管 wwwroot、App_Data、logs) │ │ └─ SslPlatform.Licensing/ 授权契约库(含硬编码公钥表) │ ├─ tools/ │ │ └─ SslPlatform.LicenseIssuer.Web/ 签发工具(含 README、Engine/、App_Data/、docs/images/) │ └─ tests/ │ ├─ SslPlatform.Tests/ 单元测试 │ └─ integration/ 集成测试(PowerShell) └─ frontend/ 平台前端 SPA(Vue 3 + Vite) ``` ## 八 系统截图路径 backend\src\SslPlatform.Api\docs\images\