























项目地址:https://github.com/Paper-Dragon/py-auth
基于 FastAPI 的软件授权服务,支持设备心跳校验、多产品授权策略、易支付对接、Web 管理后台,提供 Python / Go / TypeScript 三端客户端 SDK。
发布日期:2026-06-10
client_secret 按产品/套餐独立配置/pay、订单管理、异步/同步回调,接入 ezfpy 官方 SDKget_plan_info / get_payment_context,客户端可查询档位、价格、付费状态start_background_refresh 支持非阻塞软启动模式DetachedInstanceErroris_authorized 与 manual_plan 状态不同步TZ 控制的问题pip install py-auth-clientclient_secret 解析产品)实际使用中,我直接使用 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访问地址:
查看日志:
docker compose logs -f auth-servicepython -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 为强密码auth_data 中,删除容器不会丢失数据PUBLIC_BASE_URL 为 HTTPS 域名,否则支付页链接无法正确生成env.example 配置| 页面 | 路径 | 权限 |
|---|---|---|
| 概览 | /overview | 登录用户 |
| 设备管理 | /devices | 登录用户 |
| 产品管理 | /products | 管理员 |
| 订单管理 | /orders | 管理员 |
| 易支付 | /epay | 管理员 |
| 系统配置 | /settings | 管理员 |
| 用户管理 | /users | 管理员 |
| 审计日志 | /audit-logs | 管理员 |
Python
pip install py-auth-clientGo
go get github.com/Paper-Dragon/py-auth/client/goPyPI 地址:https://pypi.org/project/py-auth-client/
| 参数 | 是否必需 | 说明 |
|---|---|---|
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_secretclient_secret 是可信接入标识,发行时硬编码在源码中随安装包分发:
plansoftware_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 |
cache_validity_days 控制%ProgramData%\.RuntimeRepository),AES-256-GCM 加密get_authorization_info 只读本地、不联网,其中 cache_remaining_time 是本地缓存剩余有效期,不是服务端授权到期时间授权失败:密钥不匹配
client_secret 是否与后台对应产品的密钥一致client_secret网络连接失败
server_url 是否正确debug=True 查看详细错误信息设备 ID 变化
SECRET_KEY、CLIENT_SECRET、默认管理员密码PUBLIC_BASE_URL 为对外 HTTPS 域名.env 完成易支付商户配置并测试连接localhost)X-Forwarded-Proto / Hostclient_secret 与授权策略,客户端硬编码对应标识此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。