临时LICENSE授权,采用到期方法
- 定义一个ept_license的装饰器处理授权相关信息
- ept_license,定义好软件LICENSE的过期时间,比如2023-12-31之前有效
- 当你的GUI程序到期就抛出raise RuntimeError,指定错误信息是LICENSE过期就行了。
import datetime
def ept_license(func):
"""LICENSE授权相关信息"""
def wrapper():
d1 = datetime.date(2023, 12, 31)
d2 = datetime.date.today()
print(f"EPT LICENSE start. end time is {d1}. now time is {d2}")
if d2 > d1:
raise RuntimeError(
"EPT LICENSE authorization has expired. Please contact ept to purchase,tel:+86 xxxxxxxx")
func()
return wrapper
@ept_license
def say_whee():
print("Whee!")
@ept_license
class Whee(object):
pass
# say_whee()
whee = Whee()
基于机器码的网络LINCENSE授权
- LICENSE授权方式,客户拿到LINCENSE授权码,在应用程序上输入LICENSE激活工具
- LICENSE激活后的设备绑定及判断是通过os.environ获取COMPUTERNAME属性,比对完成的
- 场景一:客户已经激活系统,ept_license装饰器,满足license_num条件(有激活码)和license_chaeck条件(绑定本台设备),所以提示授权有效
- 场景二:客户将激活系统LICENSE文件拷贝到其他设备上使用,满足license_num(有激活码)但不满足license_check(绑定本台设备的条件),所以提示授权无效
- 场景三:客户输入不正确LICENSE(LICENSE无效、错误输入、LICENSE过期、LICENSE授权数量已达到最大数),则满足有license_num但云端LICENSE校验不通过
- 场景四:客户输入正确的激活码,则满足license_num,并通过云端LICENSE校验,写入本地LICENSE文件并绑定设备
import os
import requests
def ept_license(func):
"""LICENSE授权相关信息"""
def wrapper(*args, **kwargs):
# 本机识别号
pc = os.environ
license_num = "xxxx-xxxx-xxxx-xxxx"
if license_num: # LICENSE已经存在的情况
license_check = pc.get('COMPUTERNAME') == 'VIC20230807001' # 校验LICENSE是否是本机的LICENSE
print(f"pc is {pc.get('COMPUTERNAME')}, check result is {license_check}")
if not license_check: # 本机未授权
raise RuntimeError(
"EPT LICENSE authorization has expired. Please contact ept to purchase,tel:+86 xxxxxxxx")
else: # 不存在LICENSE
license_num = kwargs.get("license_num")
if not license_num: # 未传入LICENSE
raise RuntimeError(
"EPT LICENSE authorization has expired. Please contact ept to purchase,tel:+86 xxxxxxxx")
else:
result = requests.get(f"http://xxx.xxx.com/key={license_num}") # 系统校验LICENSE接口
if result.status_code != 200: # LICENSE无效,错误输入、LICENSE过期、LICENSE授权数量已经达到最大数
raise RuntimeError(
"EPT LICENSE authorization has expired. Please contact ept to purchase,tel:+86 xxxxxxxx")
else:
print(f"EPT LICENSE start. end time is 2099-12-31.")
func()
return wrapper
@ept_license
def say_whee():
print("Whee!")
@ept_license
class Whee(object):
pass
# say_whee()
whee = Whee()
LICENSE认证流程和授权优化
1 云平台生成LICENSE
- MD5算法生成
- test_16key
# 16位大写字母加数字组合
import hashlib
string = 'license_no' # 数据库license ID自增
def md5value(key):
input_name = hashlib.md5()
input_name.update(key.encode("utf-8"))
return (input_name.hexdigest())[8:-8].upper()
license = md5value(string)
# 假设结果:AAAA-BBBB-CCCC-DDDD
2 客户端使用LICENSE
-
2.1客户端输入LICENSE,调用云平台接口
- 请求信息包含LICENSE和机器识别码(CPU/BIOS/主板序列号信息)
- request
-
协议:HTTP 接口:/register header: body:{'license': 'AAAA-BBBB-CCCC-DDDD', 'cpu': 'xxxxxxxx', 'bios':'xxxxx','main board': 'xxxxxx' }
3 云平台收到LICENSE绑定设备申请
3.1 云平台数据库查找当前LICENSE状态
3.2 LICENSE无效/过期/已使用/超过最大授权数量/等其他不正确状态
- Response
{
code: 400、401、402,
message: "LICENSE不正确、过期、已使用"
data: None
}
3.3 LICENSE可用
- 使用私钥加密 机器标识码 和 授权信息
- 需要私钥加密的信息
{
"is_permanently_valid": False,
"expiration_time": "2025-12-12 00:00:00",
"version": "v1.0.0",
"tag": ["全功能版本", ''],
"CPU序列号": "BFEBFBFF000806C1",
"主板序列号": "L1HF22C001K",
"Bios序列号": "PF3NE6JE",
}
- 加密后返回给客户端
- test.py
import rsa,json
data = {
"is_permanently_valid": False,
"expiration_time": "2025-12-12 00:00:00",
"version": "v1.0.0",
"tag": "全功能版本",
"CPU序列号": "BFEBFBFF000806C1",
"主板序列号": "L1HF22C001K",
"Bios序列号": "PF3NE6JE",
}
data = json.dumps(data)
# 导入密钥
with open('public.pem', 'r') as f:
pubkey = rsa.PublicKey.load_pkcs1(f.read().encode())
# 私钥加密
crypto = rsa.encrypt(data.encode(), pubkey)
print("加密后的文本:", crypto)
# 结果b"*\x94:!\xbd\x18r\x00g\x80\xec'\x1b\xeb7j\x17\xd8\xf1\x1c\x02^\xb"
- Response
{
code: 200,
data: "*\x94:!\xbd\x18r\x00g\x80\xec'\x1b\xeb7j\x17\xd8\xf1\x1c\x02^\xb7P\x12.\x96O\t\xe0K\xe4F\xaa\xe5\xb2\x00\xe5c\xe5\x8d\xe5\x16\xe8\xee1\xa8\x1e\xef\xe6\xf3\xc5mV\x9c\xc7ATA][6\xc9x\x8c\xf9H\\xd2\xa1H$\xe6(\xd6\xcfp\x8du]\x9a\xfcz\xae\x13:\xd6\xa5<f\xa3\m,X6\x87\x15j\x08B/t\xc9\xdb#\xed\x07\xacR\x8a\x7f\x1b\xf8\xc0\x02\e\xbe\xb6\xdc\xb0\xf7\xbf\x1d\xe3\x051 \xa6\xf2\x99E?\x07X\x9d2D\xb5\x0b\xb3\xe6\xc3\xba\xf8\x1c1[\x047\x92!q@\xb2\x1a\xa3\x00\xa22\x9f\xa2\xf6\xd1\x03\xd0\xfe\xb3\xf4\xb2KH2|@\r\xcb\xd0.\xef\x93\xa2H,\xeb\xb5&hnT\x0e\xac\xb3\xe5\x03\xaa{P%<\xe5\xc0V\x94\x1d\xb1\xd2ZA\xa7w\xb8\xa7E-+\xdb\xd5\x8c\xf0\xa0\xe7mN\xdda\xf2\x06\xc8{\xad)l\xbcbj`W\x94\xf4*\xbd\xff\xc1\x99\x7fL\x1aX\x87\xc6\xe4\xe2\x0f\x87\xd1\xa52\xb1dN~\x95pt\x8b\xf9R\xa8LX4\xe9Y\xb6L\x97S\x17m\xe9\xa1\x9f\xaf\xd6)Y\x80\xde\x90-\xb4\x17\x8br0E<J\xadE)6n\xbb\xd3)_T\x98\xd4`\xfd\x0b-\x0b\x98t/\x85[\xf4\xb2\x9c\x9a\xfa\xfdnL\xf1\x0b\x06\xd1\x9a<K\x89<\x08&\xde\xf6+GJ?\xce\xefr+\xffga\r\x8a\xcel\xc9x\xc3\x9c\x92\xfe\x11\x91\xcf]\x04%\xd4pk\x8b\xa4\xf6Q-\xec\xac7\xe0c\xb5\x1fi\x9a:\x8dP\x94WS\x14\xc8\x18O|\xda\xf5\xdbR\xfb\x1c\xe1/\x99'>\x01\xe3\x85\xd3\xf7J\x88$\x19\xaf)\xba\xad\x0fM\xd0\xbf\xb37\x85\xbd\x86\x06'\xc8h\x163.\xd5G=\x0eCP\x1fm\xbc\xfb\xbe\x91\x13\x90\x11\xd0\xfc\x10\xa1\x14\xbf\xb9\x0c-\xdc!7\x1a\xe0\x98\xcf#,H\x07[F\xfc^\xa0Q\xf1G4\xc9\xcec\xa1\xf3\x0b\x9c\x0eh>K\x13\xa5\x83\xe5\x8c5\x02\x1c\xd1\xd1zh\x1f\x0c5m\xaa\x07\x96"
}
4 客户端将结果保存到本地文件
save.file(file_name="LICENSE")
5 客户端认证后使用
客户端读取本地LICENSE文件,使用RSA公钥解密,获取授权信息。通过验证后使用软件。