快速开始
本指南帮你在十分钟内完成:部署服务端 → 签发许可证 → 在应用中验证。
第一步:启动服务端
docker compose up -d
lmcli init --admin admin@example.com
第二步:签发一张许可证
lmcli license create \
--product "MyApp" \
--type subscription \
--seats 5 \
--expires 2026-12-31
第三步:在你的应用中激活
选择下方任意一种语言的 SDK,调用 activate 即可完成设备绑定与授权校验。
部署服务端
系统要求
| 组件 | 最低要求 | 推荐配置 |
|---|---|---|
| CPU / 内存 | 2 核 / 4 GB | 4 核 / 8 GB |
| 数据库 | PostgreSQL 14+ | PostgreSQL 16 |
| 缓存(可选) | — | Redis 7 |
| 运行时 | Docker 24+ | Docker 26+ / Compose v2 |
端口说明
| 端口 | 服务 | 说明 |
|---|---|---|
8443 | API 服务 | SDK 与第三方系统接入入口(HTTPS) |
8080 | 管理后台 | Web 控制台 |
5099 | 浮动授权服务 | 企业内网席位分配 |
核心概念
- 产品(Product):你要授权分发的软件,所有许可证都归属于某个产品。
- 许可证(License):一张授权凭证,包含类型(永久 / 订阅 / 试用)、席位数与到期时间。
- 激活(Activation):将许可证与具体设备指纹绑定的过程,消耗一个席位。
- 浮动授权(Floating License):由内网服务器按并发数动态分配席位,设备退出即释放。
- 宽限期(Grace Period):设备断网后仍可离线运行的天数,可按产品配置。
SDK 总览
五种官方 SDK 提供一致的接口设计:activate(激活)、verify(校验)、heartbeat(心跳)、deactivate(释放)。
| 语言 | 包名 | 最低版本 |
|---|---|---|
| C# / .NET | LicenseManager.Client.Sdk | .NET 6 |
| Node.js | @license-manager/sdk | Node 18 |
| Python | licensemanager-sdk | Python 3.9 |
| Go | github.com/license-manager/sdk-go | Go 1.21 |
| Rust | license_manager | Rust 1.75 |
C# / .NET
dotnet add package LicenseManager.Client.Sdk
using LicenseManager.Client.Sdk;
using LicenseManager.Client.Sdk.Models;
var client = new LicenseManagerClient(new LicenseManagerOptions
{
BaseUrl = "https://api.licensemanager.cn",
ApiKey = "keyId:secret",
});
var result = await client.Activations.ActivateAsync(new ActivationRequest
{
ActivationKey = "LM-XXXX-XXXX-XXXX",
HardwareId = "hw-001",
});
if (result.Success)
Console.WriteLine("激活成功");
else
Console.WriteLine($"激活失败:{result.FailureCode} {result.FailureMessage}");
Node.js
npm install @license-manager/sdk
import { LicenseManagerClient } from "@license-manager/sdk";
const client = new LicenseManagerClient({
baseUrl: "https://api.licensemanager.cn",
apiKey: "keyId:secret",
});
const result = await client.activations.activate({
activationKey: "LM-XXXX-XXXX-XXXX",
hardwareId: "hw-001",
});
if (result.success) console.log("激活成功");
else console.error(`激活失败:${result.failureCode} ${result.failureMessage}`);
Python
pip install licensemanager-sdk
from licensemanager_sdk import LicenseManagerClient, ActivationRequest
client = LicenseManagerClient(
base_url="https://api.licensemanager.cn",
api_key="keyId:secret",
)
result = client.activations.activate(
ActivationRequest(activation_key="LM-XXXX-XXXX-XXXX", hardware_id="hw-001")
)
if result.success:
print("激活成功")
else:
print(f"激活失败:{result.failure_code} {result.failure_message}")
Go
go get github.com/license-manager/sdk-go
package main
import (
"fmt"
lm "github.com/license-manager/sdk-go"
)
func main() {
client, err := lm.NewClient(lm.ClientOptions{
BaseURL: "https://api.licensemanager.cn",
APIKey: "keyId:secret",
})
if err != nil {
panic(err)
}
result, err := client.Activations.Activate(lm.ActivationRequest{
ActivationKey: "LM-XXXX-XXXX-XXXX",
HardwareID: "hw-001",
})
if err != nil {
panic(err)
}
if result.Success {
fmt.Println("激活成功")
} else {
fmt.Printf("激活失败:%s %s\n", result.FailureCode, result.FailureMessage)
}
}
Rust
[dependencies]
license_manager = "1.0"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
use license_manager::{ActivationRequest, Client, ClientConfig};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new(
ClientConfig::new("https://api.licensemanager.cn").with_api_key("keyId:secret"),
)?;
let result = client
.activate(&ActivationRequest {
activation_key: "LM-XXXX-XXXX-XXXX".into(),
hardware_id: Some("hw-001".into()),
hostname: None,
os_version: None,
sdk_version: None,
user_account: None,
})
.await?;
if result.success {
println!("激活成功");
} else {
println!("激活失败:{:?} {:?}", result.failure_code, result.failure_message);
}
Ok(())
}
REST API 参考
所有接口均基于 HTTPS + JSON,路由无前缀(/v1/...)。认证通过 Authorization 头完成,支持三种方案:
| 方案 | 格式 | 适用场景 |
|---|---|---|
Bearer | Authorization: Bearer <JWT> | 用户登录后的会话调用(管理后台 / 门户) |
ApiKey | Authorization: ApiKey <keyId>:<secret> | 服务端到服务端集成 |
Hmac | Authorization: Hmac <keyId>:<signature> | 高安全场景:签名为 HMAC-SHA256(secret, timestamp + "\n" + body)(hex 小写)。secret 通过 X-LicenseManager-Api-Key 头单独提供(仅用于服务端校验,不参与签名);时间戳通过 X-LicenseManager-Timestamp 头提供(Unix 秒,容差 ±300 秒) |
默认配置下客户端激活类接口(activate / verify / heartbeat / deactivate)允许匿名调用,可通过服务端配置 Auth:AllowPublicActivation=false 收紧为强制认证。
| 方法 | 路径 | 说明 |
|---|---|---|
POST | /v1/customer/licenses/activate | 激活设备(请求体 activationKey / hardwareId / hostname) |
POST | /v1/customer/licenses/verify | 校验许可证有效性(licenseKey / hardwareId) |
POST | /v1/customer/licenses/heartbeat | 设备心跳续约(licenseKey / hardwareId) |
POST | /v1/customer/licenses/deactivate | 释放设备席位(licenseKey / hardwareId) |
请求与响应字段统一为 camelCase;成功响应信封 {success:true,data,...},错误信封 {success:false,error:{code,message},...}。
示例:校验许可证
curl -X POST https://api.licensemanager.cn/v1/customer/licenses/verify \
-H "Authorization: ApiKey $KEY_ID:$SECRET" \
-H "Content-Type: application/json" \
-d '{"licenseKey": "LM-XXXX-XXXX-XXXX", "hardwareId": "dev-01"}'
完整的字段定义请参阅仓库中的《LicenseManager-Platform-API-Spec》。
错误码
| 错误码 | HTTP | 说明 | 处理建议 |
|---|---|---|---|
LICENSE_NOT_FOUND | 422 | 许可证不存在 | 检查 key 是否输入正确 |
LICENSE_EXPIRED | 422 | 许可证已过期 | 引导用户续期 |
LICENSE_REVOKED | 422 | 许可证已被吊销 | 联系管理员确认 |
LICENSE_SUSPENDED | 422 | 许可证已被挂起 | 联系管理员恢复 |
ACTIVATION_LIMIT_REACHED | 422 | 激活席位已满 | 释放闲置设备或扩容 |
HARDWARE_MISMATCH | 422 | 设备指纹不匹配 | 重新激活当前设备 |
rate_limit_exceeded | 429 | 请求过于频繁 | 按 Retry-After 头退避重试 |
activate / verify 等业务失败统一返回 HTTP 422,错误信封的 error.message 携带上表中的机读 failureCode;仅认证/权限类错误返回 401/403。
故障排查
激活提示 ACTIVATION_LIMIT_REACHED
登录管理后台查看该许可证的设备列表,释放不再使用的设备;或在后台将设备绑定重置后重新激活。
离线环境验证失败
确认应用内嵌的是当前签发密钥对应的公钥;检查设备系统时间是否准确(证书有效期依赖本地时钟)。
Docker 部署后无法访问管理后台
检查 docker compose logs api 输出,确认数据库迁移已完成;并确认防火墙放行了 8080 / 8443 端口。