ล็อกฟีเจอร์ตามแพ็กเกจด้วย Entitlements
ทำ feature flag ผูกกับ license: แยกแพ็กเกจ Basic/Pro ด้วย entitlements ที่ฝังอยู่ใน payload ที่เซ็นแล้ว ตรวจ offline ได้ พร้อมตัวอย่าง hasEntitlement ครบทั้ง 3 SDK (JS, Python, C#)
แทนที่จะ build แอปคนละไฟล์สำหรับแพ็กเกจ Basic กับ Pro คุณ ship แอปตัวเดียว แล้วปลดล็อกฟีเจอร์ตามสิทธิ์ที่ติดมากับคีย์ของลูกค้าแต่ละคนได้ — ด้วย entitlements ของ KeyThai มันคือ feature flag แบบหยาบ ๆ (เช่น export.pdf, premium, api.access) ที่ผูกกับ policy
ทำไมต้อง entitlements (ไม่เช็คชื่อแพ็กเกจเอง)
ถ้าโค้ดคุณ hardcode ว่า “ถ้า plan == pro ให้เปิด X” พอเพิ่มแพ็กเกจใหม่หรือทำโปร พิเศษ ต้องแก้โค้ดทุกที่ entitlements แยกแนวคิด “สิทธิ์” ออกจาก “ชื่อแพ็กเกจ” คุณปรับว่าแพ็กเกจไหนได้ฟีเจอร์อะไรจาก policy ฝั่ง dashboard โดยไม่ต้องแก้แอป
จุดเด่น: ฝังในลายเซ็น → ตรวจ offline ได้
entitlements ถูกฝัง ภายใน payload ที่เซ็นด้วย Ed25519 (รหัสถูกเรียงลำดับ ก่อนเซ็นเพื่อให้ canonical) เมื่อแอปตรวจลายเซ็นผ่าน ก็เชื่อรายการสิทธิ์ได้เลยโดยไม่ต้อง ต่อเน็ต และปลอมไม่ได้ — เพราะถ้าแก้ entitlements ลายเซ็นจะไม่ตรงทันที
เช็คด้วย hasEntitlement (ทั้ง 3 SDK)
ทุก SDK มีฟังก์ชัน hasEntitlement ที่ปลอดภัยต่อค่า null/ไม่มี entitlements (คืน false เสมอ) จึงเรียกได้โดยไม่ต้องเช็ค null เอง — คีย์ Basic ที่ไม่มีสิทธิ์ จะได้ผลลัพธ์ “ปิดฟีเจอร์” โดยอัตโนมัติ:
import { verifyLicFile, hasEntitlement } from "keythai-sdk";
// payload เซ็นด้วย Ed25519 → entitlements ฝังข้างใน เชื่อถือได้แบบ offline
const lic = await verifyLicFile(jwk, licFileContents);
if (!lic.valid) throw new Error(lic.reason);
// แอปตัวเดียว แต่ปลดล็อกฟีเจอร์ตามชุดสิทธิ์ของคีย์แต่ละใบ
if (hasEntitlement(lic.payload, "export.pdf")) enablePdfExport();
if (hasEntitlement(lic.payload, "api.access")) enableApiTab();
// ค่าเริ่มต้นปลอดภัย: คีย์ Basic ไม่มี entitlement → คืน false เสมอ
if (!hasEntitlement(lic.payload, "premium")) showUpgradePrompt();from keythai import verify_lic_file, has_entitlement
lic = verify_lic_file(jwk, lic_file_contents)
if not lic["valid"]:
raise RuntimeError(lic["reason"])
# has_entitlement คืน False เมื่อ payload เป็น None หรือไม่มี entitlements
if has_entitlement(lic.get("payload"), "export.pdf"):
enable_pdf_export()
if not has_entitlement(lic.get("payload"), "premium"):
show_upgrade_prompt() # ผู้ใช้แพ็กเกจ Basicusing KeyThai;
LicFileResult lic = KeyThaiVerifier.VerifyLicFile(licFileContents, jwk);
if (!lic.Valid) throw new Exception(lic.Reason);
// SignedLicenseResponse.Entitlements เป็น IReadOnlyList<string>? (null เมื่อไม่มี)
if (KeyThaiVerifier.HasEntitlement(lic.Payload, "export.pdf"))
EnablePdfExport();
if (!KeyThaiVerifier.HasEntitlement(lic.Payload, "premium"))
ShowUpgradePrompt(); // Basic tierตัวอย่าง: Basic vs Pro ด้วยคีย์คนละชุดสิทธิ์
สร้าง 2 policy: Basic (ไม่มี entitlement) และ Pro (มี export.pdf, api.access, premium) ออกคีย์จาก policy ที่ลูกค้าซื้อ แอปตัวเดียวจะเปิด/ปิดเมนูตามสิทธิ์ของคีย์ พอลูกค้าอัปเกรด คุณแค่ออกคีย์ Pro หรือเปลี่ยน policy — ไม่ต้อง build/ship แอปใหม่ และเพราะ hasEntitlement คืน false เมื่อไม่มีสิทธิ์ ค่าเริ่มต้นจึงปลอดภัย (fail-closed)
อยากให้ผลลัพธ์เชื่อถือได้แม้ออฟไลน์ ควรตรวจลายเซ็นก่อนเสมอ — อ่าน ตรวจ license แบบ offline ด้วย Ed25519 ดูชนิดฟิลด์และฟังก์ชันทั้งหมดได้ที่ เอกสาร