授權場景
Entitlement 與 Usage:功能權限和計次額度
用 Entitlement 決定功能能不能執行,用 Usage 記錄成功完成了幾次;兩者不能互相替代。
Entitlement 保護功能,Usage 計算成果
Entitlement
表示 License 是否擁有某個功能代碼,例如 HDL_EXPORT、ADVANCED_REPORT 或 AUTOMATION。
檢查時機:每次真正執行高價值功能之前。
Usage
表示某個可計量工作已成功完成幾次,例如產生報告、匯出檔案或執行一次付費分析。
累計時機:工作成功且輸出可交付之後。
功能入口的正確寫法
"""Protect a real feature boundary, not only a visible UI button."""
from keygen_device_sdk import FeatureNotLicensedError, LicenseSDKError
def export_hdl(client) -> None:
try:
state = client.validate_or_raise()
state.require("YOUR_FEATURE_CODE")
print("Exporting HDL...")
except FeatureNotLicensedError:
print("This License does not include HDL export")
except LicenseSDKError as exc:
print(f"Export blocked: {exc}")
計次工作的正確順序
- 先驗證授權
確認 License 有效,必要時也確認 Entitlement。
- 把結果寫入暫存位置
完成計算或產檔,但先不要把正式輸出交付給使用者。
- 向 Server 增加 Usage
increment_usage(amount)只接受正整數;可一次增加 1、2、3 或其他合理批次量。 - 成功後才正式交付
若 Server 接受計數,將暫存結果移到正式位置;若額度已滿,刪除暫存結果。
"""Publish a metered result only after the Server accepts Usage."""
from pathlib import Path
from keygen_device_sdk import GatewayError, LicenseSDKError
def generate_report(client, amount: int = 1) -> None:
staged = Path("staging/report.pdf")
try:
state = client.validate_or_raise()
print("Current Usage:", state.uses, "/", state.max_uses)
staged.parent.mkdir(parents=True, exist_ok=True)
staged.write_bytes(b"example report")
usage = client.increment_usage(amount)
print(f"Publish {staged}; Usage accepted: {usage.uses}/{usage.max_uses}")
except GatewayError as exc:
staged.unlink(missing_ok=True)
print(f"Usage rejected [{exc.code or exc.status_code}]: {exc}")
except (LicenseSDKError, OSError, ValueError, TypeError) as exc:
staged.unlink(missing_ok=True)
print(f"Metered job failed: {exc}")
Server 週期自動歸零
管理員可在單張 License 選擇每日、每週或每月自動歸零,並指定 IANA 時區。每日在當地午夜、每週在星期一午夜、每月在 1 日午夜進入新週期。歸零由 Server 執行,不採信 Client 時鐘;Gateway 在每次 Usage 增加前也會檢查週期,避免排程延遲造成誤拒絕。
設計檢查清單
- Entitlement Code 使用常數並由管理員確認
- 受保護函式不依賴 UI 狀態
- 失敗工作不扣 Usage
- 重試不會重複扣量
- Usage 不取代 Machine activation
- 撤銷或過期時功能入口確實停止