LSY ODS 授权 SDK
lsyods-license-sdk 是 LSY ODS 提供的 Python 公用 SDK,用于机器身份识别、离线软件授权以及部署制品签名。SDK 提供稳定的机器指纹、安装实例 ID、Ed25519 许可证签发与校验、部署 ZIP 签名与验签,以及许可证状态判断等能力。
- 作者:成都领数云科技有限公司
- 项目地址:https://github.com/9kl/lsyods_license_sdk
- 开源许可:MIT
功能特性
- 在 Windows 和 Linux 上计算带版本标识、不可逆的机器指纹。
- 为不同产品生成独立的安装实例 ID。
- 签发采用 Ed25519 数字签名的离线许可证。
- 使用显式配置的可信公钥集合校验许可证和部署制品签名。
- 将许可证与产品、软件版本、产品版本、安装实例 ID 和机器指纹绑定。
- 判断订阅授权、永久授权、授权已过期和授权尚未生效等状态。
- 通过
supersedes_license_id保留许可证续期关系。 - 将服务端确认的部署方式与 ZIP 摘要一起签名,供客户端独立验签。
产品版本表示 basic、advanced 等商业版本。具体功能或模块是否可用,由被授权产品根据商业版本自行判断。永久授权没有到期时间,但仍然只适用于签名声明中指定的软件版本。
安装
从 PyPI 安装:
pip install lsyods-license-sdk
使用 uv 安装:
uv add lsyods-license-sdk
SDK 要求 Python 3.10 或更高版本。
生成许可证签名密钥
SDK 提供 lsyods-license-keygen 命令,用于生成软件许可证专用的 Ed25519 密钥对。默认情况下,命令会要求输入密码,并使用该密码加密生成的私钥。
PowerShell 示例:
$env:LSYODS_LICENSE_KEY_PASSWORD = Read-Host "请输入密钥密码" -MaskInput
lsyods-license-keygen `
--private-key D:\secure\license-private.pem `
--public-key D:\secure\license-public.pem
命令执行成功后会输出公开的 key_id 和 public_key_base64,供被授权产品配置可信公钥。私钥只能由受控的许可证签发服务访问,禁止将私钥或私钥密码分发到客户端或被授权产品中。
在具备可靠系统访问控制的自动化环境中,可以使用 --no-password 生成不加密的私钥。此时必须通过操作系统文件权限严格保护私钥文件。
机器指纹
from lsyods_license_sdk import calculate_machine_fingerprint
machine_fingerprint = calculate_machine_fingerprint()
print(machine_fingerprint) # sha256:<64位小写十六进制字符>
SDK 使用带版本标识的域分隔符,对操作系统中相对稳定的机器标识进行哈希计算。返回结果不会包含原始的 Windows MachineGuid 或 Linux machine-id。
部署制品签名
许可证签名和部署制品签名必须使用不同的密钥对。请使用 lsyods-artifact-keygen 为部署服务端生成专用的制品签名密钥,不要复用许可证签名密钥。
lsyods-artifact-keygen --private-key artifact-private.pem --public-key artifact-public.pem
该命令默认从 LSYODS_ARTIFACT_KEY_PASSWORD 环境变量读取私钥密码,并输出客户端配置所需的 key_id 和 public_key_base64。
服务端只会对已经通过安全审计和超级管理员审批的 ZIP 文件进行签名。部署方式由服务端审批记录提供,ZIP 中不需要额外的部署清单文件。
部署服务端和客户端通过 SDK 使用同一套制品签名协议:
from pathlib import Path
from lsyods_license_sdk import (
create_artifact_signature,
load_artifact_private_key,
verify_artifact_signature,
)
package = Path("deployment.zip")
private_key = load_artifact_private_key(Path("artifact-private.pem"))
signature = create_artifact_signature(package, private_key, "powershell_deploy")
verified = verify_artifact_signature(
package,
signature,
"powershell_deploy",
{signature["key_id"]: "<public_key_base64>"},
signature["sha256"],
)
许可证签名协议和部署制品签名协议使用不同的域分隔符。生产环境还必须为两类签名分别使用独立私钥,以便单独控制权限、轮换和吊销密钥。
签发许可证
许可证只能在受控的服务端环境中签发:
from datetime import datetime, timedelta, timezone
from pathlib import Path
from lsyods_license_sdk import (
generate_installation_id,
issue_license,
load_private_key,
)
now = datetime.now(timezone.utc).replace(microsecond=0)
private_key = load_private_key(
Path("D:/secure/license-private.pem"),
password="private-key-password",
)
claims = {
"license_id": "L260819000001",
"issuer": "LSY ODS",
"customer": "示例客户",
"product": {
"code": "example-product",
"version": "V1.0",
"edition": "advanced",
},
"installation": {
"installation_id": generate_installation_id(),
"machine_fingerprint": "sha256:" + "a" * 64,
},
"license_type": "subscription",
"issued_at": now.isoformat(),
"not_before": now.isoformat(),
"expires_at": (now + timedelta(days=90)).isoformat(),
}
license_document = issue_license(claims, private_key)
签发永久许可证时,将 license_type 设置为 "perpetual",并将 expires_at 设置为 None。
校验许可证
被授权产品只保存可信公钥,并根据当前产品、安装实例和运行机器校验本地许可证:
from lsyods_license_sdk import calculate_machine_fingerprint, verify_license
trusted_keys = {
"<key_id>": "<public_key_base64>",
}
result = verify_license(
license_document,
trusted_keys,
expected_product="example-product",
expected_installation_id=installation_id,
expected_machine_fingerprint=calculate_machine_fingerprint(),
)
if not result["valid"]:
raise RuntimeError(f"许可证状态异常:{result['status']}")
licensed_version = result["claims"]["product"]["version"]
licensed_edition = result["claims"]["product"]["edition"]
被授权产品负责根据自身的版本兼容规则和功能开放规则,对 licensed_version 和 licensed_edition 进行判断。
许可证续期
续期会生成一份新的签名许可证,同时沿用原有的安装实例 ID 和机器指纹。原许可证保持不变,仍然可以独立验签。新许可证声明中可以包含:
{
"supersedes_license_id": "L260819000001"
}
该字段表示新许可证替代的历史许可证,便于保留完整的授权续期关系。
安全模型
- 系统安全依赖于妥善保护 Ed25519 私钥,而不是隐藏 SDK 的实现代码。
- 被授权产品和部署客户端只能信任明确配置的公钥。
- 许可证和制品签名文档在完成签名后必须视为不可变数据。
- 机器指纹是设备标识,不是身份认证密码或安全凭据。
- 离线授权无法阻止客户修改其完全控制的应用程序,被授权产品应在合适的信任边界执行授权检查。
- 密钥轮换时,应先将新公钥加入可信公钥集合,再使用新私钥签发许可证或签名制品。
- 许可证私钥与部署制品私钥必须分别存储、分别授权和分别轮换。
开发与构建
项目使用 uv 管理依赖,并通过 pyproject.toml 配置阿里云 PyPI 镜像:
uv sync --locked
uv run pytest
uv run pyflakes src tests
uv build --no-sources
开源许可
Copyright (c) 2026 成都领数云科技有限公司。
本项目基于 MIT 许可证 开源。
Release files for lsyods-license-sdk 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| lsyods_license_sdk-0.3.0.tar.gz | 17.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| lsyods_license_sdk-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:32.0 kB
Release files / lsyods_license_sdk-0.3.0.tar.gz
| Download URL | lsyods_license_sdk-0.3.0.tar.gz |
|---|---|
| Size | 17.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ab90bc5599c421478bc78bf8b67688edeb7bbab1bef8b64acffc6bc06d25dbef
|
|
BLAKE2b-256 checksum How to use checksums |
1bbcec99596ed3f2a36948d02d2c7fe2e16ae677476e572c0a30597053229e9b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.11
|
Release files / lsyods_license_sdk-0.3.0-py3-none-any.whl
| Download URL | lsyods_license_sdk-0.3.0-py3-none-any.whl |
|---|---|
| Size | 14.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
37f86aa69cfc3b7c9460aeda56161aa38c7f01902e4017b782b7cad4ec32e12d
|
|
BLAKE2b-256 checksum How to use checksums |
444d0845db0dafc474e8051687cbd0ab3e07bbbf5b396a0976a89d3717cfd7b8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.11
|