做独立开发或者接私活的朋友,大概率都遇到过这种情况:代码交付了,尾款拖了又拖;或者更恶心一点,客户拿到源码转手就二次售卖。我以前在群里吐槽这事,有人直接说“你这就是没上授权”,当时我还觉得加个域名验证多简单,不就是比对一下HTTP_HOST嘛,直到自己写了套授权系统的V1.0被客户三天就破解,才明白这事情水有多深。后来我一直在维护一套基于PHP的域名授权系统,最近整合成了V7.3开源版的多应用管理平台,这篇文章就把这套系统的设计思路、部署流程和踩过的坑完整记录下来,希望对正在做软件授权、SaaS服务隔离或者PHP多项目管理的朋友有帮助。
这套系统不是什么天顶星科技,但它解决了一个很实际的问题:作为一个PHP开发者,你手上有好几个产品线,每个产品对应不同的客户、不同的域名、不同的授权时长,如果每个项目都单独写一套授权逻辑,光是维护授权表格就够喝一壶的。V7.3版的核心思路是把“授权”这件事从业务代码里剥离出来,做成一个独立的管理平台,业务端只需要引入一个轻量SDK做验证,所有授权的增删改查、域名绑定、到期提醒、应用分组都在后台完成。适合的对象也很明确:用PHP写商城、CMS、企业建站、ERP系统的开发者,以及想给自己的开源项目加一道商业闭环的朋友。
1. 域名授权到底在防什么?警惕把授权系统做成“心理安慰”
动笔写代码之前,先想清楚一个元问题:域名授权系统防的到底是谁?根据我自己的实践和跟同行的交流,授权系统面对的威胁基本可以分为三个等级,不同等级对应的防护策略完全不同。
1.1 防止普通客户“换域名跑路”
这是最基本的需求。很多个人开发者交付PHP项目时,客户拿到源码后改了数据库里的域名配置,就把项目部署到另一个域名上,等于一份源码无限复制使用。域名授权的第一道防线就是做域名绑定,在授权服务端记录允许的域名列表,业务程序启动时向授权服务器发起校验,如果当前访问域名不在授权列表内,直接拒绝运行。
这里有个容易被忽视的细节:所谓“域名绑定”到底绑什么?是绑一个字符串比对HTTP_HOST,还是绑域名对应的IP,还是绑SSL证书指纹?V7.3版的策略是“域名为主、IP为辅、可选绑定证书指纹”。为什么这么设计?因为很多客户的服务器是云主机,IP会变;有些客户用的是负载均衡,请求到达你业务服务器时,HTTP_HOST可能被改写过。如果只做IP绑定,误杀率太高,售后全浪费在“帮客户解封”上了。
1.2 防止“懂一点技术”的客户篡改验证逻辑
第二道防线面对的是懂PHP、会看代码的客户。他们拿到源码后,第一件事就是全局搜索“授权”“license”“domain”这些关键词,找到验证函数,然后尝试删掉或者绕过。
应对思路是“分散验证+关键业务耦合”。不要把验证逻辑写成一个独立的authorize.php然后让业务代码include一下,这样太容易删了。更稳妥的做法是在业务代码里多个位置植入验证点,每个验证点都带上业务上下文。比如在商城系统的订单生成函数里检查授权状态,在后台登录流程里检查授权到期时间,在企业CMS的文章发布接口里检查域名合法性。这样即使客户找到了一个验证点并删掉,其他验证点依然会触发异常。
1.3 警惕“专业破解者”的逆向分析
第三类威胁是真正靠破解授权吃饭的人。他们懂抓包、懂反序列化、懂PHP混淆,甚至会去分析你SDK和服务器之间的通信协议。说实话,对于个人开发者或小团队来说,想完全防住专业破解是不现实的。
那怎么办?我的原则是“提高破解成本,降低破解收益”。具体做法:
- 核心授权逻辑永远放在服务端,客户端只做结果展示
- 通信协议包含时间戳防重放,即使被抓包,也不能简单改包绕过
- 授权状态不只在登录时验证,而是定期“心跳”校验,断线超时后业务进入降级模式
- 最关键的是,授权系统本身不要包含太多业务逻辑,即使被破解,损失也控制在一个可接受的范围内
2. 小笑V7.3的系统架构:授权服务与业务代码如何解耦
V7.3版本在架构上做了一个重要调整:把“授权验证”做成了服务端SDK模式,而不是传统的“客户端代码里写死校验逻辑”。为什么这么折腾?因为大多数PHP项目是部署在客户自己的服务器上的,如果你的授权系统要求业务代码每次启动都去请求一个第三方API,客户很容易因为服务器网络问题导致业务不可用,最后反而怪到你头上。
2.1 “远程验证为主、本地缓存为辅”的双通道设计
V7.3的授权验证流程是这样的:
- 业务程序启动时,SDK先检查本地缓存中是否有有效的授权信息
- 如果本地缓存有效且在有效期内,直接放行业务逻辑
- 如果本地缓存不存在或已过期,SDK会向授权管理平台发起远程验证请求
- 远程验证通过后,SDK会把授权结果写入本地缓存,并设置一个合理的过期时间
- 如果远程验证失败(比如服务器网络不通),SDK会根据配置的“宽容策略”决定是放行还是拦截
这个设计的核心是“本地缓存优先级高于远程校验”。你可能觉得奇怪,如果本地缓存优先,那破解者不是直接改本地缓存就行了吗?所以本地缓存必须加密存储,并且绑定服务器的机器指纹。V7.3版用的是“机器码+授权码+过期时间”的组合,客户端缓存文件中存储的是服务
