Python软件授权
2026/1/5...大约 7 分钟
Python软件授权
项目地址:https://github.com/Paper-Dragon/py-auth
基于 FastAPI 的软件授权服务,支持设备心跳校验、多产品授权策略、易支付对接、Web 管理后台,提供 Python / Go / TypeScript 三端客户端 SDK。
版本更新 (v0.1.6)
发布日期:2026-06-10
新功能
- 多产品授权体系:支持默认、手动审核、付费三种授权模式,
client_secret按产品/套餐独立配置 - 易支付集成:公开支付页
/pay、订单管理、异步/同步回调,接入 ezfpy 官方 SDK - 套餐信息 API:新增
get_plan_info/get_payment_context,客户端可查询档位、价格、付费状态 - 设备封禁与手动套餐:管理员可封禁设备或手动指定套餐档位
- 后台刷新授权:
start_background_refresh支持非阻塞软启动模式 - Go / TypeScript SDK:新增两端客户端,三端 API 对齐
- WebSocket 实时设备列表:后台设备管理全面迁移为 WebSocket 推送
- 操作审计日志:管理员操作落库,支持分页查看与按天清理
- 系统配置页:限流、自动刷新、分页等可在后台配置
改进
- 心跳统一为单次上报快照,后台线程异步补全设备信息并自动补发心跳
- 心跳解密增加产品缓存,消除每次请求的全量查询
- 手动套餐选项改由后端按设备所属产品下发
- 客户端 HTTP 超时可独立配置(心跳 / 套餐查询 / 付费上下文)
- Go 客户端 Windows 下隐藏外部命令控制台窗口
- Docker 镜像 CI 自动构建推送至 Docker Hub
修复
- 修复缓存的 Product 对象跨 Session 导致的
DetachedInstanceError - 修复取消授权或清除手动套餐时
is_authorized与manual_plan状态不同步 - 修复 SQLite 下时区不受
TZ控制的问题
发布渠道变更
- Python 客户端已迁移至 PyPI 公开发布,不再使用私有索引
- 安装方式:
pip install py-auth-client
功能概览
- 设备注册与心跳校验(AES 加密载荷,
client_secret解析产品) - 多产品授权策略:默认、手动审核、付费
- 易支付集成:公开支付页、订单管理、支付回调
- 管理员登录与用户管理
- 操作日志审计与接口限流
- Web 管理后台(设备、产品、订单、易支付、系统配置)
- 支持 SQLite 和 MySQL
服务端部署
Docker Compose 部署
实际使用中,我直接使用 SQLite 数据库,更简单方便,不需要单独部署 MySQL。
docker-compose.yaml 配置:
version: '3.8'
services:
auth-service:
image: jockerdragon/py-auth-service
build: .
container_name: auth-service
environment:
TZ: Asia/Shanghai
DATABASE_TYPE: sqlite
SQLITE_PATH: /app/data/auth.db
CLIENT_SECRET: aB3cD5eF7gH9iJ1kL3mN5oP7qR9sT1uV3wX5yZ7aB9cD1eF3gH5iJ7kL9mN1oP3qR5sT7uV9wX1yZ3
SECRET_KEY: M2nP4qR6sT8uV0wX2yZ4aB6cD8eF0gH2iJ4kL6mN8oP0qR2sT4uV6wX8yZ0aB2cD4eF6gH8iJ0
ACCESS_TOKEN_EXPIRE_MINUTES: 1440
ADMIN_USERNAME: admin
ADMIN_PASSWORD: xK9mP2qR5tV8wY
# 公网访问根地址(生产环境必填,用于易支付回调与对外支付页链接)
# PUBLIC_BASE_URL: https://auth.example.com
# 易支付(也可在后台「易支付」页面配置;留空 notify/return 时由 PUBLIC_BASE_URL 自动生成)
# EPAY_API_URL:
# EPAY_PID:
# EPAY_KEY:
# EPAY_NOTIFY_URL:
# EPAY_RETURN_URL:
ports:
- "8000:8000"
volumes:
- auth_data:/app/data
restart: unless-stopped
volumes:
auth_data:启动服务:
git clone https://github.com/Paper-Dragon/py-auth.git
cd py-auth
docker compose up -d访问地址:
- Web 管理界面:http://localhost:8000
- API 文档:http://localhost:8000/docs
查看日志:
docker compose logs -f auth-service本地运行
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -e .
Copy-Item env.example .env
cd web && pnpm install && pnpm build && cd ..
python main.py首次启动会自动创建数据库表并初始化管理员账号。
环境变量
| 变量 | 说明 |
|---|---|
DATABASE_TYPE | 数据库类型,sqlite 或 mysql |
SQLITE_PATH | SQLite 文件路径 |
SECRET_KEY | 服务端 JWT 密钥 |
CLIENT_SECRET | 默认产品的 Client Secret(心跳加解密;未登记产品使用) |
ACCESS_TOKEN_EXPIRE_MINUTES | 登录令牌过期时间(分钟) |
ADMIN_USERNAME / ADMIN_PASSWORD | 默认管理员账户 |
PUBLIC_BASE_URL | 公网访问根地址,用于易支付回调与对外支付页链接 |
EPAY_API_URL / EPAY_PID / EPAY_KEY | 易支付配置(也可在后台页面配置) |
示例见项目中的 env.example。
注意事项
- 生产环境请修改
CLIENT_SECRET、SECRET_KEY和ADMIN_PASSWORD为强密码 - 数据存储在 Docker volume
auth_data中,删除容器不会丢失数据 - 生产环境必须配置
PUBLIC_BASE_URL为 HTTPS 域名,否则支付页链接无法正确生成 - 如果需要使用 MySQL,可以参考项目中的
env.example配置
管理后台
| 页面 | 路径 | 权限 |
|---|---|---|
| 概览 | /overview | 登录用户 |
| 设备管理 | /devices | 登录用户 |
| 产品管理 | /products | 管理员 |
| 订单管理 | /orders | 管理员 |
| 易支付 | /epay | 管理员 |
| 系统配置 | /settings | 管理员 |
| 用户管理 | /users | 管理员 |
| 审计日志 | /audit-logs | 管理员 |
客户端 SDK 使用
安装
Python
pip install py-auth-clientGo
go get github.com/Paper-Dragon/py-auth/client/goTypeScript
npm i py-auth-clientPyPI 地址:https://pypi.org/project/py-auth-client/
AuthClient 参数
| 参数 | 是否必需 | 说明 |
|---|---|---|
server_url | 必填 | 服务地址 |
software_name | 必填 | 软件名称,参与授权规则(默认/手动审核/付费等) |
client_secret | 条件必填 | 可信接入标识,硬编码在发行包中,服务端据此确定套餐 plan;不同套餐/版本使用不同值 |
device_id | 可选 | 省略时自动生成或复用 |
software_version | 可选 | 软件版本 |
cache_validity_days | 可选 | 本地缓存有效期,默认 7 |
check_interval_days | 可选 | 检查间隔,默认 2 |
heartbeat_timeout_sec | 可选 | 心跳超时,默认 (3.0, 3.0) |
plan_info_timeout_sec | 可选 | 套餐查询超时,默认 (5.0, 10.0) |
payment_context_timeout_sec | 可选 | 付费上下文查询超时,默认 (5.0, 10.0) |
debug | 可选 | 开启调试日志 |
关于 client_secret
client_secret 是可信接入标识,发行时硬编码在源码中随安装包分发:
- 服务端信任该标识,用于识别客户端发行渠道/套餐,并返回对应
plan - 免费版 / Pro 版可各自硬编码不同标识
- 与
software_name分工:software_name走授权规则,client_secret走套餐归属 - 轮换
client_secret会使旧发行包标识失效,需发新包
基本使用
参考项目中的 client/python/example.py:
from py_auth_client import AuthClient, AuthorizationError
client = AuthClient(
server_url="http://localhost:8000",
software_name="我的软件",
client_secret="sk_...",
)
try:
client.require_authorization()
print("设备已授权")
except AuthorizationError as e:
print(f"授权失败: {e}")
exit(1)
info = client.get_authorization_info()
print(info)查询套餐与付费上下文
plan = client.get_plan_info()
if plan.get("success"):
print(plan.get("plan"), plan.get("price"))
if plan.get("plan_detail"):
print(plan.get("plan_detail"))
ctx = client.get_payment_context()
if ctx.get("success"):
print(ctx.get("plan"), ctx.get("can_pay"))get_plan_info() 返回产品套餐配置(档位、价格、详情等),不表示本机是否已付款。心跳返回的 authorized 表示能否上线;plan 表示当前生效档位。
后台刷新授权
适用于主线程不阻塞的场景,参考 client/python/example_background.py:
from py_auth_client import AuthClient, shutdown_auth_background_executor
client = AuthClient(
server_url="http://localhost:8000",
software_name="我的软件",
client_secret="sk_...",
)
soft, fut = client.start_background_refresh(
on_done=lambda r: print("后台刷新结果:", r)
)
if soft:
print("可先依据本地快照启动")
else:
print("无有效本地快照,需等待本次检查结果")
result = fut.result(timeout=120)
shutdown_auth_background_executor(wait=True)付费引导
未授权时可引导用户到公开支付页完成付款:
pay_url = f"{client.server_url}/pay?device_id={client.device_id}&auto_pay=1"
print(f"请在浏览器打开以下链接完成付款:{pay_url}")
input("付款完成后按回车继续...")
if client.require_authorization(raise_exception=False, force_online=True):
print("付款成功,已授权")
else:
print("仍未授权,请确认订单状态后重试")三端方法对照
| 语义 | Python | Go | TypeScript |
|---|---|---|---|
| 在线校验授权 | check_authorization | CheckAuthorization | checkAuthorization |
| 要求授权通过 | require_authorization | RequireAuthorization | requireAuthorization |
| 本地快照可软启动 | can_soft_launch | CanSoftLaunch | canSoftLaunch |
| 后台刷新授权 | start_background_refresh | StartBackgroundRefresh | startBackgroundRefresh |
| 仅读取本地授权信息 | get_authorization_info | GetAuthorizationInfo | getAuthorizationInfo |
| 查询套餐信息 | get_plan_info | GetPlanInfo | getPlanInfo |
| 查询付费上下文 | get_payment_context | GetPaymentContext | getPaymentContext |
| 清除本地缓存 | clear_cache | ClearCache | clearCache |
缓存机制说明
- 缓存有效期:默认 7 天,由
cache_validity_days控制 - 验证流程:优先尝试在线心跳,成功则更新本地缓存
- 离线支持:在线请求失败时,缓存有效期内降级使用本地快照
- 缓存位置:系统隐藏目录(Windows:
%ProgramData%\.RuntimeRepository),AES-256-GCM 加密 get_authorization_info只读本地、不联网,其中cache_remaining_time是本地缓存剩余有效期,不是服务端授权到期时间- 如果服务端拒绝授权,即使有缓存也会失败
常见问题
授权失败:密钥不匹配
- 检查
client_secret是否与后台对应产品的密钥一致 - 注意不同产品/套餐使用不同的
client_secret
- 检查
网络连接失败
- 检查
server_url是否正确 - 检查服务端是否正常运行
- 开启
debug=True查看详细错误信息
- 检查
设备 ID 变化
- 设备 ID 基于硬件信息自动生成
- 更换硬件可能导致设备 ID 变化,需要在管理界面重新授权
生产环境检查清单
更新日志
2026/6/10 15:51
查看所有更新日志
5ff9b-于95c06-于