最近用 Claude 写了几个不错的小工具,朋友用完反馈说挺好,建议我试着编写试试。这就遇到了一个很实际的问题:代码写出来容易,但怎么控制分发?
如果是网站还好说,常规用户系统就能解决,服务也都在后端。但如果是桌面程序,如果不加限制,发给一个人就等于发给了所有人。
这两天研究了一下软件授权(Licensing)的方案,主要有两种成熟的路径。这里做个技术备忘,也分享给同样的独立开发者。
方案一:离线授权(注册码模式)
这是最传统的做法,就像以前买 Shareware 软件那样。用户给你一串机器码,你发给他一个 .lic 文件或者一串注册码。
原理
核心是非对称加密(RSA)。 逻辑其实很简单:
- 开发者手里有私钥:用来生成“许可证”。
- 软件里埋了公钥:用来验证“许可证”是不是我签发的。
实现步骤
1.取指纹:客户端启动时,读取 CPU 序列号或主板 UUID,生成一个唯一的 Machine_ID。
def get_machine_id() -> str:
# Simple demo fingerprint: combine hostname + MAC
host = os.environ.get("COMPUTERNAME", "unknown")
mac = uuid.getnode() raw = f"{host}-{mac:x}"
digest = hashes.Hash(hashes.SHA256())
digest.update(raw.encode("utf-8"))
return digest.finalize().hex()
2.生成许可证:用户把 Machine_ID 发给你。我在本地用私钥,把 Machine_ID + 过期时间 打包加密,生成注册码。
代码很好排版就贴图片了
payload = {
"product": "DemoTool",
"machine_id": machine_id,
"expires_at": expires_at,
}
license_str = sign_license(private_key, payload)
3.校验:用户填入注册码。客户端用公钥解密,对比解密出来的 Machine_ID 和本机是否一致。如果不一致,说明把别人的码拿来用了,直接报错。
优缺点
- 好处:省心,不用维护服务器。软件离线也能用。
- 坏处:控制力弱。一旦码发出去,想撤销很难(除非更新软件拉黑名单)。而且如果用户改系统时间,可能绕过有效期检查。
完整演示效果
方案二:在线授权(登录/激活模式)
主流软件都采用这种模式。
原理
把验证逻辑放在服务端。客户端只负责上报信息,程序能否使用由服务器说了算。
实现逻辑
- 预埋数据:我在数据库里先生成一堆激活码(或者用户付费后生成)。
- 激活请求: 用户第一次打开软件,输入激活码。 客户端发送请求:
POST /activate,带上激活码+本机指纹。 - 服务端绑定: 服务器查一下这个码是不是有效的?有没有被用过? 如果没有问题,就把这个
激活码和当前的本机指纹绑定死,并在数据库标记为“已激活”。 返回一个 Token 给客户端保存。 - 日常检查: 软件每次启动(或定期),带着 Token 问一下服务器:“我还能用吗?” 服务器如果发现这个码被退款了、或者被封禁了,就返回 False,软件自动退出。
优缺点
-
好处:控制力强。可以随时封禁违规用户,可以做按月订阅(服务端判断时间到了没),可以限制一个码只能由 2 台电脑用(服务端统计一下绑定数就行)。
-
坏处:麻烦。需要写后端和服务器,成本高很多。
如果嫌麻烦,,可以试试Distromate分发助手,因为最近我自己的软件有很多需要尝试变现,所有自己封装了一套在线授权分发工具,用起来效果还可以,借助AI集成远程授权很方便,可以远程授权,增量更新还有后台数据洞察,有需要可以试试。
我的选择与建议
对于我们这种想通过 AI 快速出产品验证想法的开发者:
起步阶段或者简单程序可以考虑离线方案,尽量还是采用远程授权的方案,Distromate分发助手
附:一点代码实现的坑
-
离线方案:记得校验一下系统时间。如果用户把系统时间调回 1970 年,你的过期判断可能会失效。简单的办法是记录最后一次运行的时间戳,如果当前时间小于历史记录,肯定有问题。
-
代码混淆:Python/JS 写的代码如果不编译或混淆,别人反编译一下就能把你的校验逻辑删了。虽然防不住小人,但至少得用 PyInstaller nuitka打包一下,愿意付费尊重知识的人永远都有。