CardAuth 卡密授权管理系统 开发文档
这个项目是什么
CardAuth 是一套轻量级的卡密(激活码)+ 机器授权管理系统:软件作者用它生成卡密、管理授权、发展代理分销,最终用户在公开商城在线购买,客户端程序通过 API 校验授权是否有效。适用于软件授权、会员激活、IPTV/App 直购发卡等场景,自带安装统计、版本推送与公告推送,可以当一个小型「授权中心」用。
技术栈与架构
| 层 | 技术 |
|---|---|
| 后端 | PHP 8.1+ 自研框架(Router + Middleware + Controller,无 Laravel 等重型框架) |
| 数据库 | MySQL 8.0+,表前缀 ca_,统一 utf8mb4 |
| 前端 | Vue 3 + Element Plus + Pinia + ECharts,Vite 构建 |
| 部署 | Docker 多阶段构建(Nginx + PHP-FPM + Supervisor 同容器,外挂 MySQL)或传统 Nginx + PHP-FPM |
后端分层:app/Controllers 放 12 个业务模块控制器,app/Core 是框架核心(Router / Controller / Database / Middleware / Validator),app/Middleware 放 Auth、JWT、RateLimit、ApiKey、Blacklist、Role 等中间件,app/Services 放 Jwt / Blacklist / Permission / Snowflake 等服务层。API 返回统一 {"code": 200/400/401/403/404/429/500, "data"/"message"} 结构。
仓库结构
├── backend/ # PHP 后端
│ ├── app/ # Controllers / Core / Middleware / Services
│ ├── config/ # 配置文件
│ ├── database/ # schema.sql 与 migrations/ 升级脚本
│ ├── routes/ # 路由定义
│ ├── public/ # Web 根目录(前端构建产物 + uploads 上传目录)
│ └── tests/ # PHPUnit 测试
├── frontend/ # Vue 3 前端(src/api、views、stores、router、components)
├── docker/ # nginx.conf、supervisord.conf、entrypoint.sh
├── deploy/ # 传统部署的 nginx.conf 等
├── php/ # uploads.ini(PHP 上传限制,compose 挂载进容器)
├── docs/ # 文档与截图
├── Dockerfile # 多阶段构建:Node 构建前端 + PHP 运行时
├── docker-compose.yml# 编排:MySQL 8.0 + 应用容器
├── deploy.sh # 传统部署一键脚本
└── .env.docker # Docker 环境变量模板
本地开发环境
方式一(推荐,Docker):
cp .env.docker .env
# 编辑 .env:设置 JWT_SECRET 与数据库密码
docker compose up -d
首次启动自动完成前端构建、数据库初始化(backend/database/schema.sql 挂载为 MySQL 初始化脚本)、Nginx 与 PHP-FPM 启动。compose 中应用容器实际映射 8881:80,访问 http://localhost:8881(README 快速开始里写的 8080 是旧示例,以 compose 的 8881 为准)。
方式二(传统部署):环境要求 Nginx 1.18+、PHP 8.1+(启用 PDO、PDO_MySQL、mbstring、bcmath)、MySQL 8.0+、Node.js 18+(仅构建期需要)、Composer。手动流程:
mysql -u root -p < backend/database/schema.sql
cd backend && cp .env.example .env # APP_ENV=production、APP_DEBUG=false、填 DB_* 与 JWT_SECRET
cd backend && composer install --no-dev --optimize-autoloader
cd frontend && npm install && npm run build
cp -r frontend/dist/* backend/public/
Nginx 核心配置见 deploy/nginx.conf:SPA fallback try_files $uri $uri/ /index.html,/api 路由回 index.php,并 deny 掉 .env/.sql/.log 与 storage|config|routes 目录。也可以直接跑 sudo bash deploy.sh your-domain.com,脚本会做环境检查、构建、部署、建库、Nginx 配置与权限设置。
配置项说明
.env(后端 backend/.env,手动部署)关键键:APP_ENV、APP_DEBUG、DB_HOST/DB_PORT/DB_NAME/DB_USER/DB_PASS/DB_PREFIX(默认 ca_)、JWT_SECRET。
.env.docker(compose 用):
| 键 | 含义 | 默认值 |
|---|---|---|
APP_URL |
对外访问地址,支付回调 notify_url/return_url 用它拼 |
http://localhost:8080(compose 内回退 http://localhost:8881) |
MYSQL_ROOT_PASSWORD |
MySQL root 密码 | root_secret_change_me |
DB_NAME / DB_USER / DB_PASS |
业务库与账号 | card_auth / card_auth / card_auth_pass |
JWT_SECRET |
JWT 密钥,留空自动生成(容器重启会变,生产务必固定) | 空 |
TURNSTILE_SITE_KEY / TURNSTILE_SECRET_KEY |
Cloudflare Turnstile 人机验证,留空跳过 | 空 |
PAYMENT_TYPE |
支付网关类型 | epay |
PAYMENT_API_URL / PAYMENT_APP_ID / PAYMENT_APP_KEY |
易支付网关地址、商户 ID、密钥 | 空 |
应用容器还注入 APP_ENV=production、APP_DEBUG=false、DB_HOST=db、DB_PREFIX=ca_。MySQL 容器启动参数带 --default-time-zone=+08:00(v1.1.1 起时间统一北京时间)。compose 把 ./php/uploads.ini 挂载进容器固化 PHP 上传限制,把 ./backend/public/uploads 挂载出来持久化安装包与头像——改这两处必须走挂载,直接进容器改会在重建后丢失。
数据库与升级
全新安装直接导入 backend/database/schema.sql;已有库按版本增量执行 backend/database/migrations/ 下的 SQL(例如 20261008_add_installations_and_versions.sql 新增 ca_installations、ca_project_versions 表)。主要业务表:项目、套餐(card types)、卡密、授权(ca_authorizations)、订单、代理与额度日志、优惠券、黑名单、公告(ca_announcements)、安装记录、项目版本。
API 体系与鉴权
三种鉴权并存:
| 类型 | 说明 |
|---|---|
| JWT Token | 登录后获得,`Authorization: Bearer *** 小时 |
| API Key | 每个项目一把,仅用于授权验证类接口,请求头 X-Api-Key |
| 公开接口 | 无需认证,60 秒内 30 次频率限制 |
客户端对接最常用的三个接口(均带项目 API Key):POST /api/public/verify 验证授权并附带版本更新字段;POST /api/public/installations/check-update 检查更新并登记安装;POST /api/public/installations/heartbeat 轻量心跳更新 last_online_at。商城侧走 GET /api/public/projects、GET /api/public/projects/{id}/card-types、POST /api/public/orders、GET /api/public/orders/query。管理端接口按模块划分:/api/projects、/api/cards、/api/authorizations、/api/orders、/api/users、/api/agents、/api/coupons、/api/blacklists、/api/system/*、/api/installations、/api/versions 等,完整列表见 README 的 API 文档章节。
支付后发卡流程(重点改造点)
异步回调、同步完成、手动补单、免费商品统一进 OrderController::processOrderPaid():
- 订单带
bot_qq+contact_qq:创建或续费 QQ 授权记录; - 订单不带
bot_qq(App/IPTV 直购):进入自动发卡——从同项目同套餐的未用卡池取 1 张,绑定机器码后标记已使用,订单写入card_id;机器码从contact_info里按正则MACHINE:([A-Za-z0-9\-_]+)解析,未填则用AUTO-{订单号}占位; - 卡池无卡:订单仍标记已支付,
card_id为空,需管理端补卡后手动处理。
v1.3.0 修复了支付同步回调「签名验证失败」:签名改为用网关原始回调串 sign_params 重算(按网关规则跳过空值),同步补单失败会自动查 orders/query 兜底显示卡密。
定时任务
0 */6 * * * curl -s http://your-domain/api/cron/notify-expiring > /dev/null
/api/cron/notify-expiring 无需认证,检查即将过期的授权并通过 SMTP 发提醒邮件到联系人 QQ 邮箱(contact_qq@qq.com)。SMTP 在管理端「系统配置 → SMTP 邮件配置」里填写,可发测试邮件。
二次开发要点
- 管理员登录带 Cloudflare Turnstile 人机验证;代理登录/注册在 v1.3.0 起改为自绘 SVG 图形验证码(
GET /api/public/captcha,4 位数字、无 GD 依赖、Session 存 5 分钟一次性),改登录逻辑时注意stores/user.js的login()第 4 个参数是{turnstile_token}或{captcha_code}对象。 - 强制更新只是给客户端的提示:
is_force/min_client_version只让verify、check-update返回update_required=true,不阻断授权结果。 - 时间口径:MySQL
+08:00、PHPAsia/Shanghai,新增时间字段不要再用 UTC。 - 上传相关改动记得配合
php/uploads.ini挂载与backend/public/uploads持久化卷,否则容器重建丢安装包。 - 代理看不到代理信息、项目管理员只操作绑定项目,加新后台页面时记得同步
app/Middleware的角色校验。
相关链接
- Gitea 仓库:http://127.0.0.1:3200/jinghui/CardAuth
- 系统内置文档页:部署后访问
/#/docs(含自动发卡、安装统计、版本推送、API 对接说明) - License:MIT