# QCloudTools **Repository Path**: DLarpx/QCloudTools ## Basic Information - **Project Name**: QCloudTools - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-14 - **Last Updated**: 2026-07-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # QCloudTools 基于 .NET 10 的腾讯云 SSL 证书与 DNS 解析管理门户,集成两步验证、自动化证书续期、多渠道通知与实时数据大屏。 ## 功能特性 ### 核心模块 - **管理员认证**:单一管理员账户,BCrypt 密码哈希(cost=12),TOTP 两步验证,10 个备用恢复码,连续 5 次失败锁定 15 分钟 - **SSL 证书管理**:免费 DV 证书申请(DNS 验证自动创建 `_acme-challenge` 记录)、到期前自动续期、过期证书自动清理、单证书下载与批量打包下载 - **DNS 解析管理**:DNSPod 域名与解析记录 CRUD、自动清理证书申请残留的验证记录、解析量统计拉取 - **数据大屏**:KPI 卡片、DNS 解析量趋势图、近期操作日志、SignalR 实时事件推送、60 秒轮询刷新 - **通知服务**:邮件(MailKit SMTP)、钉钉群机器人(HMAC-SHA256 加签)、企业微信群机器人,每渠道独立开关与测试 - **调度任务**:Cron 表达式驱动(含秒级),证书扫描续期、过期清理、DNS 残留清理、解析量拉取四任务,失败指数退避重试 ### 安全防护 - HTTPS 强制重定向 + HSTS - 严格 CSP(同源 + WASM `wasm-unsafe-eval`,禁止 `unsafe-inline`) - 安全响应头(X-Content-Type-Options、X-Frame-Options、Referrer-Policy、Permissions-Policy) - AES-256-GCM 敏感配置加密存储(密钥取自 `APP_ENCRYPTION_KEY` 环境变量) - JWT 30 分钟访问令牌 + HttpOnly Secure SameSite=Strict 刷新 Cookie 7 天 - 登录限流(IP 5 次/分钟)与 API 限流(已认证 60 次/分钟) - ForwardedHeaders 反代场景真实 IP 识别 - 全局异常处理不暴露 `ex.Message` - FluentValidation 输入验证 ## 技术栈 | 层 | 技术 | |---|---| | 后端 | .NET 10、ASP.NET Core、SignalR | | 前端 | Blazor WebAssembly(hosted 模式) | | 数据 | SQLite、SqlSugar ORM(CodeFirst) | | 腾讯云 | TencentCloudSDK.NET(Ssl + Dnspod) | | 安全 | BCrypt.Net、Otp.NET、QRCoder、JWT Bearer | | 通知 | MailKit、钉钉 Webhook、企业微信 Webhook | | 调度 | BackgroundService + Cronos | | 部署 | Docker(aspnet:10.0-alpine) | ## 项目结构 ``` src/ ├── QCloudTools.Core/ # 实体、接口、常量、Result/ApiResponse 封装 ├── QCloudTools.Models/ # DTO 与 FluentValidation 验证器 ├── QCloudTools.Services/ # 业务服务实现 │ ├── Auth/ # 认证、TOTP、JWT、审计 │ ├── Persistence/ # SqlSugar 仓储、DbInitializer │ ├── Security/ # AES-256-GCM 配置加密 │ ├── TencentCloud/ # SSL 证书与 DNSPod 适配器 │ ├── Notification/ # 邮件、钉钉、企业微信三渠道 │ ├── Scheduler/ # Cron 定时任务宿主 │ ├── Packages/ # 打包下载令牌管理 │ └── Hubs/ # SignalR NotificationHub ├── QCloudTools.Api/ # ASP.NET Core 入口、控制器、中间件 │ ├── Controllers/ # Auth/Ssl/Dns/Notification/Scheduler/Dashboard │ └── Middlewares/ # 认证、限流、CSP、安全头、全局异常 ├── QCloudTools.Web/ # Blazor WebAssembly 客户端 │ ├── Pages/ # 12 个页面(主页/登录/大屏/SSL/DNS/...) │ ├── Shared/ # 布局与共享组件(Modal/Toast/StatusBadge/...) │ └── Services/ # ApiClient、AppStateService、ToastService └── QCloudTools.Tests/ # xUnit 单元测试(28 个) ``` ## 本地开发 ### 前置条件 - .NET 10 SDK - (可选)Docker,用于容器化部署验证 ### 启动开发服务器 ```powershell git clone https://gitee.com/DLarpx/QCloudTools.git cd QCloudTools dotnet restore dotnet build dotnet run --project src/QCloudTools.Api/QCloudTools.Api.csproj --launch-profile http ``` 访问 `http://localhost:5000`。 开发环境默认凭据(来自 `Properties/launchSettings.json`): - 用户名:`admin` - 密码:`Admin@123456` - 首次登录会引导绑定 TOTP ### 运行测试 ```powershell dotnet test ``` ## Docker 部署 ### 1. 准备环境变量 ```bash cp .env.example .env ``` 编辑 `.env`,至少填入以下两个必填项: ```bash # 生成方式:openssl rand -base64 32 APP_ENCRYPTION_KEY= # 生成方式:openssl rand -base64 48 Jwt__SigningKey=<至少 32 字节的随机字符串> ``` 可选填入腾讯云凭据(不填则进入离线模式,仅记录日志不阻止启动): ```bash TencentCloud__SecretId=<你的腾讯云 SecretId> TencentCloud__SecretKey=<你的腾讯云 SecretKey> ``` ### 2. 构建与启动 ```bash docker compose up -d --build ``` 容器监听 8080 端口,数据持久化到宿主机 `./data/` 目录(SQLite 数据库、SSL 证书、打包文件)。 ### 3. 反向代理(推荐生产环境) 容器仅监听 HTTP 8080,生产环境应在前面加 Nginx 或 Caddy 提供 HTTPS: ```nginx server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # SignalR WebSocket 支持 location /hubs/ { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } } ``` ### 健康检查 容器内置 HEALTHCHECK 探测 `/api/health`: ```bash docker inspect --format='{{.State.Health.Status}}' qcloud-tools ``` ## 环境变量说明 | 变量 | 必填 | 默认值 | 说明 | |---|---|---|---| | `APP_ENCRYPTION_KEY` | 是 | — | AES-256-GCM 加密密钥(base64,至少 32 字节) | | `Jwt__SigningKey` | 是 | — | JWT 签名密钥(至少 32 字节) | | `INIT_ADMIN_PASSWORD` | 否 | 随机生成 | 初始管理员密码(仅首次启动) | | `ASPNETCORE_ENVIRONMENT` | 否 | Production | 运行环境 | | `ASPNETCORE_URLS` | 否 | `http://+:8080` | 监听地址 | | `ConnectionStrings__Default` | 否 | `Data Source=/data/qcloud.db` | SQLite 连接字符串 | | `TencentCloud__SecretId` | 否 | — | 腾讯云 SecretId | | `TencentCloud__SecretKey` | 否 | — | 腾讯云 SecretKey | | `TencentCloud__Region` | 否 | `ap-guangzhou` | 腾讯云地域 | | `Certificate__RenewalThresholdDays` | 否 | 30 | 证书续期阈值天数 | | `Security__TrustedProxies` | 否 | `["127.0.0.1","::1"]` | 受信任反代 IP(JSON 数组) | | `Cors__AllowedOrigins` | 否 | `[]` | 允许的跨域源(JSON 数组,默认同源) | > **注意**:ASP.NET Core 环境变量配置映射规则为 `__`(双下划线)→ `:`。例如 `Jwt__SigningKey` 对应配置键 `Jwt:SigningKey`。 ## API 摘要 所有 API 返回统一 `ApiResponse` 格式: ```json { "code": 200, "message": "success", "data": { /* 业务数据 */ } } ``` | 模块 | 端点 | 说明 | |---|---|---| | 认证 | `POST /api/auth/login` | 登录(用户名 + 密码 + TOTP) | | | `POST /api/auth/refresh` | 刷新访问令牌(依赖 HttpOnly Cookie) | | | `POST /api/auth/logout` | 登出 | | | `GET /api/auth/setup-totp` | 获取 TOTP 绑定信息 | | | `POST /api/auth/bind-totp` | 确认绑定 TOTP | | | `POST /api/auth/change-password` | 修改密码(需当前密码 + TOTP) | | | `POST /api/auth/change-username` | 修改用户名(需当前密码 + TOTP) | | | `GET /api/auth/me` | 获取当前用户信息 | | SSL | `GET /api/ssl/list` | 证书列表 | | | `POST /api/ssl/sync` | 从腾讯云同步证书 | | | `POST /api/ssl/add-domain` | 添加待申请域名 | | | `GET /api/ssl/pending-domains` | 待申请域名列表 | | | `POST /api/ssl/apply/{domainId}` | 申请证书 | | | `GET /api/ssl/download/{id}` | 下载单个证书 zip | | | `DELETE /api/ssl/{id}` | 删除证书 | | | `GET /api/ssl/packages` | 打包文件列表 | | DNS | `GET /api/dns/domains` | 域名列表 | | | `GET /api/dns/records?domain=` | 解析记录列表 | | | `POST /api/dns/records` | 创建记录 | | | `PUT /api/dns/records/{id}` | 更新记录 | | | `DELETE /api/dns/records/{id}` | 删除记录 | | | `GET /api/dns/traffic-stats?domain=&days=7` | 解析量统计 | | 通知 | `GET /api/notification/config` | 通知配置 | | | `PUT /api/notification/config` | 更新配置 | | | `POST /api/notification/test` | 测试发送 | | 调度 | `GET /api/scheduler` | 任务列表 | | | `PUT /api/scheduler/{name}` | 更新任务配置 | | | `POST /api/scheduler/{name}/trigger` | 立即触发 | | 大屏 | `GET /api/dashboard/stats` | KPI 统计 | | | `GET /api/dashboard/traffic-trend?days=7` | 解析量趋势 | | | `GET /api/dashboard/recent-logs?limit=20` | 近期日志 | | | `GET /api/dashboard/pending-domains` | 待申请域名 | | | `GET /api/dashboard/latest-package` | 最新打包 | | 实时 | `GET /hubs/notifications` | SignalR Hub(JWT 认证) | | 健康 | `GET /api/health` | 健康检查(无需认证) | ### SignalR 客户端事件 | 事件 | 触发时机 | |---|---| | `ReceiveNotification` | 通知渠道发送完成 | | `CertificateUpdated` | 证书同步/申请/删除/续期完成 | | `DnsRecordChanged` | DNS 记录增删改完成 | | `SchedulerTaskCompleted` | 调度任务执行完成 | | `PackageCreated` | 打包文件生成完成 | ## 调度任务默认配置 | 任务 | Cron 表达式(6 段含秒) | 说明 | |---|---|---| | 证书扫描续期 | `0 0 */6 * * *` | 每 6 小时 | | 过期证书清理 | `0 0 3 * * *` | 每天 03:00 | | DNS 验证记录清理 | `0 0 */12 * * *` | 每 12 小时 | | DNS 解析量统计拉取 | `0 0 1 * * *` | 每天 01:00 | 所有 Cron 表达式可在后台调度配置页修改,支持热加载无需重启。 ## 常见问题 ### Q: 首次启动后如何获取管理员密码? A: 若未设置 `INIT_ADMIN_PASSWORD` 环境变量,系统会生成强随机密码并输出到容器日志。查看日志: ```bash docker compose logs qcloud-tools | grep "管理员密码" ``` ### Q: 忘记管理员密码怎么办? A: 停止容器,删除 `./data/qcloud.db` 文件后重新启动,会重新初始化管理员账户(注意:此操作会清除所有数据)。 ### Q: 忘记 TOTP 验证码怎么办? A: 首次绑定 TOTP 时会生成 10 个备用恢复码,使用任一恢复码即可登录。若恢复码也丢失,需删除数据库重新初始化。 ### Q: 腾讯云凭据未配置会有什么影响? A: 系统会进入离线模式,启动时记录警告日志但不阻止启动。DNS 与证书自动申请功能不可用,其他功能(如登录、调度配置查看)正常。 ### Q: SignalR 连接失败怎么办? A: 反向代理必须正确转发 WebSocket 升级请求(参考上方 Nginx 配置的 `/hubs/` location 块)。客户端内置指数退避重试(0s/2s/4s/8s/16s)。 ### Q: 容器健康检查显示 unhealthy? A: 检查 `/api/health` 端点是否可访问: ```bash docker exec qcloud-tools wget -qO- http://localhost:8080/api/health ``` 应返回 `{"code":200,"message":"ok","data":null}`。 ## 许可证 私有项目,未授权使用。