golang简单高效的许可证管理插件库lk的使用

Golang简单高效的许可证管理插件库lk的使用

lk是一个简单高效的Golang许可证管理库,它可以生成包含任意数据(如用户邮箱、截止日期等)的许可证文件,并支持验证这些许可证。

工作原理

  1. 生成一个私钥(并保持安全)
  2. 将你想要提供的数据(截止日期、用户邮箱等)转换为字节数组(使用json或gob等)
  3. 库获取数据并创建一个加密签名的哈希,附加到数据中
  4. 将结果转换为Base64/Base32/Hex字符串并发送给最终用户:这就是许可证
  5. 当用户启动程序时,加载许可证并使用公钥验证签名
  6. 验证许可证密钥中的数据(如截止日期)

完整示例

1. 生成新许可证

// 首先,你需要一个由`lkgen gen`生成的base32编码的私钥
// 注意你可能更愿意从文件中读取它,并且它应该保持机密(即不要随应用程序分发!)
const privateKeyBase32 = "FD7YCAYBAEFXA22DN5XHIYLJNZSXEAP7QIAACAQBANIHKYQBBIAACAKEAH7YIAAAAAFP7AYFAEBP7BQAAAAP7GP7QIAWCBCRKQVWKPT7UJDNP4LB5TXEQMO7EYEGDCE42KVBDNEGRIYIIJFBIWIVB6T6ZTKLSYSGK54DZ5VX6M5SJHBYZU2JXUFXJI25L2JJKJW4RL7UL2XBDT4GKYZ5IS6IWBCN7CWTMVBCBHJMH3RHZ5BVGVAY66MQAEYQEPSS2ANTYZIWXWSGIUJW3MDOO335JK3D4N3IV4L5UTAQMLS5YC7QASCAAUOHTZ5ZCCCYIBNCWBELBM===="

// 解组私钥
privateKey, err := lk.PrivateKeyFromB32String(privateKeyBase32)
if err != nil {
    log.Fatal(err)
}

// 定义许可证中需要的数据
// 这里我们使用一个被编组成json的结构体,但最终你只需要一个[]byte
doc := struct {
    Email string    `json:"email"`
    End   time.Time `json:"end"`
}{
    "user@example.com",
    time.Now().Add(time.Hour * 24 * 365), // 1年
}

// 将文档编组为[]bytes(这是我们的许可证将包含的数据)
docBytes, err := json.Marshal(doc)
if err != nil {
    log.Fatal(err)
}

// 用私钥和文档生成你的许可证
license, err := lk.NewLicense(privateKey, docBytes)
if err != nil {
    log.Fatal(err)
}

// 许可证的b32表示,这是你给客户的东西
licenseB32, err := license.ToB32String()
if err != nil {
    log.Fatal(err)
}
fmt.Println(licenseB32)

2. 验证许可证

// 一个之前生成的b32编码的许可证。在实际应用中你应该从文件中读取它...
const licenseB32 = "FT7YOAYBAEDUY2LDMVXHGZIB76EAAAIDAECEIYLUMEAQUAABAFJAD74EAAAQCUYB76CAAAAABL7YGBIBAL7YMAAAAD73H74IAFEHWITFNVQWS3BCHIRHIZLTORAGK6DBNVYGYZJOMNXW2IRMEJSW4ZBCHIRDEMBRHAWTCMBNGI3FIMJSHIYTSORTGMXDOMBZG43TIMJYHAVTAMR2GAYCE7IBGEBAPXB37ROJCUOYBVG4LAL3MSNKJKPGIKNT564PYK5X542NH62V7TAUEYHGLEOPZHRBAPH7M4SC55OHAEYQEXMKGG3JPO6BSHTDF3T5H6T42VUD7YAJ3TY5AP5MDE5QW4ZYWMSAPEK24HZOUXQ3LJ5YY34XYPVXBUAA===="

// 公钥b32编码,使用`lkgen pub my_private_key_file`从私钥生成
// 它应该硬编码在你的应用程序中
const publicKeyBase32 = "ARIVIK3FHZ72ERWX6FQ6Z3SIGHPSMCDBRCONFKQRWSDIUMEEESQULEKQ7J7MZVFZMJDFO6B46237GOZETQ4M2NE32C3UUNOV5EUVE3OIV72F5LQRZ6DFMM6UJPELARG7RLJWKQRATUWD5YT46Q2TKQMPPGIA===="

// 解组公钥
publicKey, err := lk.PublicKeyFromB32String(publicKeyBase32)
if err != nil {
    log.Fatal(err)
}

// 解组客户许可证
license, err := lk.LicenseFromB32String(licenseB32)
if err != nil {
    log.Fatal(err)
}

// 验证许可证签名
if ok, err := license.Verify(publicKey); err != nil {
    log.Fatal(err)
} else if !ok {
    log.Fatal("Invalid license signature")
}

result := struct {
    Email string    `json:"email"`
    End   time.Time `json:"end"`
}{}

// 解组文档
if err := json.Unmarshal(license.Data, &result); err != nil {
    log.Fatal(err)
}

// 现在你只需要检查截止日期是否在当前时间之后,然后就可以继续了!
if result.End.Before(time.Now()) {
    log.Fatalf("License expired on: %s", result.End.Format("2006-01-02"))
} else {
    fmt.Printf(`Licensed to %s until %s`, result.Email, result.End.Format("2006-01-02"))
}

3. 完整示例

// 创建一个新的私钥:
privateKey, err := lk.NewPrivateKey()
if err != nil {
    log.Fatal(err)
}

// 创建一个许可证文档:
doc := MyLicence{
    "test@example.com",
    time.Now().Add(time.Hour * 24 * 365), // 1年
}

// 将文档编组为json字节:
docBytes, err := json.Marshal(doc)
if err != nil {
    log.Fatal(err)
}

// 用私钥和文档生成你的许可证:
license, err := lk.NewLicense(privateKey, docBytes)
if err != nil {
    log.Fatal(err)
}

// 将新许可证编码为b64,这是你给客户的东西
str64, err := license.ToB64String()
if err != nil {
    log.Fatal(err)
}
fmt.Println(str64)

// 获取公钥。公钥应该硬编码在你的应用程序中以检查许可证
// 不要分发私钥!
publicKey := privateKey.GetPublicKey()

// 验证许可证:
if ok, err := license.Verify(publicKey); err != nil {
    log.Fatal(err)
} else if !ok {
    log.Fatal("Invalid license signature")
}

// 解组文档并检查截止日期:
res := MyLicence{}
if err := json.Unmarshal(license.Data, &res); err != nil {
    log.Fatal(err)
} else if res.End.Before(time.Now()) {
    log.Fatalf("License expired on: %s", res.End.String())
} else {
    fmt.Printf(`Licensed to %s until %s \n`, res.Email, res.End.Format("2006-01-02"))
}

这个库使用椭圆曲线数字签名算法(使用elliptic.P384)来签名许可证文件,并且许可证可以以易于分发的格式(如base32编码字符串)进行编组。


更多关于golang简单高效的许可证管理插件库lk的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang简单高效的许可证管理插件库lk的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 许可证管理插件库 lk 使用指南

lk 是一个简单高效的 Golang 许可证管理库,可以帮助开发者轻松实现软件许可证的生成、验证和管理功能。下面我将详细介绍如何使用这个库。

安装

首先使用 go get 安装 lk 库:

go get github.com/yourusername/lk

基本用法

1. 创建许可证

package main

import (
	"fmt"
	"github.com/yourusername/lk"
)

func main() {
	// 创建新的许可证
	license := lk.NewLicense()
	
	// 设置许可证属性
	license.Set("name", "John Doe")
	license.Set("email", "john@example.com")
	license.Set("expiry", "2023-12-31")
	license.Set("features", []string{"feature1", "feature2"})
	
	// 生成许可证密钥
	key, err := license.Generate("your-secret-key")
	if err != nil {
		fmt.Println("生成许可证失败:", err)
		return
	}
	
	fmt.Println("生成的许可证密钥:", key)
}

2. 验证许可证

package main

import (
	"fmt"
	"github.com/yourusername/lk"
)

func main() {
	// 假设这是从用户获取的许可证密钥
	licenseKey := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
	
	// 验证许可证
	license, err := lk.Validate(licenseKey, "your-secret-key")
	if err != nil {
		fmt.Println("许可证验证失败:", err)
		return
	}
	
	// 获取许可证信息
	name, _ := license.Get("name")
	email, _ := license.Get("email")
	expiry, _ := license.Get("expiry")
	
	fmt.Printf("许可证信息:\n名称: %s\n邮箱: %s\n过期时间: %s\n", name, email, expiry)
}

高级功能

1. 自定义验证规则

package main

import (
	"fmt"
	"time"
	"github.com/yourusername/lk"
)

func main() {
	licenseKey := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
	
	// 自定义验证函数
	customValidator := func(license *lk.License) error {
		// 检查过期时间
		expiry, err := license.Get("expiry")
		if err != nil {
			return fmt.Errorf("无效的许可证: 缺少过期时间")
		}
		
		expiryTime, err := time.Parse("2006-01-02", expiry.(string))
		if err != nil {
			return fmt.Errorf("无效的过期时间格式")
		}
		
		if time.Now().After(expiryTime) {
			return fmt.Errorf("许可证已过期")
		}
		
		// 检查必要特性
		features, err := license.Get("features")
		if err != nil {
			return fmt.Errorf("无效的许可证: 缺少特性列表")
		}
		
		requiredFeatures := []string{"feature1", "feature2"}
		for _, req := range requiredFeatures {
			found := false
			for _, f := range features.([]string) {
				if f == req {
					found = true
					break
				}
			}
			if !found {
				return fmt.Errorf("缺少必要特性: %s", req)
			}
		}
		
		return nil
	}
	
	// 带自定义验证的许可证检查
	license, err := lk.ValidateWith(licenseKey, "your-secret-key", customValidator)
	if err != nil {
		fmt.Println("许可证验证失败:", err)
		return
	}
	
	fmt.Println("许可证验证通过:", license)
}

2. 许可证续期

package main

import (
	"fmt"
	"time"
	"github.com/yourusername/lk"
)

func renewLicense(oldKey string, newExpiry time.Time) (string, error) {
	// 验证旧许可证
	license, err := lk.Validate(oldKey, "your-secret-key")
	if err != nil {
		return "", fmt.Errorf("无法续期无效的许可证: %v", err)
	}
	
	// 更新过期时间
	license.Set("expiry", newExpiry.Format("2006-01-02"))
	
	// 生成新许可证
	newKey, err := license.Generate("your-secret-key")
	if err != nil {
		return "", fmt.Errorf("生成新许可证失败: %v", err)
	}
	
	return newKey, nil
}

func main() {
	oldKey := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
	newExpiry := time.Now().AddDate(1, 0, 0) // 延长一年
	
	newKey, err := renewLicense(oldKey, newExpiry)
	if err != nil {
		fmt.Println("续期失败:", err)
		return
	}
	
	fmt.Println("新的许可证密钥:", newKey)
}

最佳实践

  1. 密钥安全:确保你的密钥安全,不要硬编码在代码中,可以使用环境变量或配置文件。

  2. 定期检查:在应用程序中定期检查许可证有效性,而不仅仅在启动时。

  3. 特性控制:使用许可证中的特性列表来控制应用程序的不同功能模块。

  4. 错误处理:为用户提供友好的错误信息,同时记录详细的验证错误日志。

  5. 离线验证:考虑实现离线验证机制,允许用户在无网络连接时使用。

lk 库提供了简单而强大的许可证管理功能,通过合理使用可以有效地保护你的软件产品。根据你的具体需求,可以进一步扩展和定制验证逻辑。

回到顶部