当前位置: 首页 > news >正文

Python软件授权验证完整方案(免费卡密系统搭建)

本文将带你完整实现一个带卡密验证的Python软件授权系统,包含:卡密验证、MD5签名防篡改、时间戳防重放、心跳保活、强制版本更新、公告推送等功能。无需自建服务器,对接即用。

一、为什么需要软件授权验证?

作为独立开发者,你辛辛苦苦写出来的软件,最怕的就是被人随意复制、破解、传播。一套完善的授权验证系统,可以帮你:

  • 控制软件使用期限(天卡/周卡/月卡/年卡/终身)

  • 绑定设备防止账号共享

  • 远程控制软件状态(禁用/启用)

  • 获取软件使用统计

  • 推送更新公告

市面上有不少付费的授权平台,但如果你只是想快速实现功能、又不想花冤枉钱,卡密通这个平台可以免费使用,我已经用了很久,稳定可靠。

二、完整代码

python

# ============================================================ # ceshi.py — 带卡密验证的测试软件 # 打包命令:pyinstaller --onefile --noconsole ceshi.py # ============================================================ # ---------- 卡密系统配置 ---------- SIGN_KEY = "keyt@2026" # 签名密钥(后台获取) API_BASE_URL = "https://www.keyt.cn/kami/你的用户名/check.php" APP_NAME = "a" # 应用名称 TIMESTAMP_MAX_DIFF = 120 # 时间戳容差(秒) HEARTBEAT_INTERVAL = 55 # 心跳间隔(秒) MAX_HEARTBEAT_FAILS = 5 # 最大连续心跳失败次数 APP_VERSION = "1.0.0" # 当前版本号 ENABLE_VERSION_CHECK = True # 版本检查开关 ENABLE_CARD_CACHE = True # 卡密缓存开关 ENABLE_HEARTBEAT = True # 心跳检测开关 import tkinter as tk from tkinter import ttk, messagebox import hashlib import time import uuid import threading import platform import subprocess import ssl import urllib.request import urllib.parse import os import sys import webbrowser import re # ================== 获取机器码 ================== def get_machine_code(): """获取本机机器码(MAC地址)""" try: mac = uuid.getnode() mac_str = ':'.join(('%012X' % mac)[i:i+2] for i in range(0, 12, 2)) return mac_str.replace(':', '') + "MAC" except: try: if platform.system() == "Windows": result = subprocess.run(['getmac', '/v', '/fo', 'csv'], capture_output=True, text=True, encoding='gbk') lines = result.stdout.split('\n') for line in lines[1:]: if 'Wi-Fi' in line or '以太网' in line or 'Ethernet' in line or 'WLAN' in line: parts = line.split(',') if len(parts) >= 2: mac = parts[0].strip('"').replace('-', '') if mac and mac != '00-00-00-00-00-00' and len(mac) >= 12: return mac + "MAC" except: pass try: result = subprocess.run(['ipconfig', '/all'], capture_output=True, text=True, encoding='gbk') mac_pattern = r'([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})' matches = re.findall(mac_pattern, result.stdout) if matches: mac = ''.join(matches[0]).replace(':', '').replace('-', '') if mac and len(mac) >= 12: return mac[:12] + "MAC" except: pass return "获取失败" # ================== MD5加密 ================== def md5_encrypt(text): return hashlib.md5(text.encode('utf-8')).hexdigest().lower() # ================== HTTP请求 ================== def http_get(url): try: ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE headers = { 'Cache-Control': 'no-cache', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } req = urllib.request.Request(url, headers=headers) response = urllib.request.urlopen(req, timeout=10, context=ssl_context) headers_dict = dict(response.getheaders()) xsign2 = headers_dict.get('X-Sign2', '') content = response.read().decode('utf-8') return { 'status': response.status, 'text': content, 'xsign2': xsign2 } except Exception as e: return { 'status': 0, 'text': 'error|网络错误', 'xsign2': '' } # ================== 签名校验(核心防篡改)================== def verify_response(raw_response, xsign2): pos = raw_response.find("|sign=") if pos == -1: return "" body = raw_response[:pos] sign = raw_response[pos + 6:] local_sign = md5_encrypt(body + SIGN_KEY) if xsign2 and local_sign == xsign2.lower(): pass elif local_sign == sign.lower(): pass else: return "" last_pipe = body.rfind('|') if last_pipe == -1: return "" ts_str = body[last_pipe + 1:] if not ts_str.isdigit(): return "" ts = int(ts_str) now_ts = int(time.time()) diff = abs(now_ts - ts) if diff > TIMESTAMP_MAX_DIFF: return "" return body[:last_pipe] # ================== 获取开关状态 ================== def get_card_switch(): for retry in range(3): try: t = time.strftime("%Y%m%d%H%M%S") url = f"{API_BASE_URL}?act=get_switch&app={APP_NAME}&t={t}" result = http_get(url) if result['status'] == 200: biz = verify_response(result['text'], result['xsign2']) if biz: return "CARD_ON" if "CARD_ON" in biz else "CARD_OFF" except: pass if retry < 2: time.sleep(0.5) return "CARD_ON" # ================== 获取公告 ================== def fetch_notice(): try: url = f"{API_BASE_URL}?act=get_notice&app={APP_NAME}&t={int(time.time())}" result = http_get(url) if result['status'] == 200: notice = result['text'].strip() return notice if notice else "暂无公告" except: pass return "暂无公告" # ================== 获取最新版本号 ================== def fetch_latest_version(): try: url = f"{API_BASE_URL}?act=get_version&app={APP_NAME}&t={int(time.time())}" result = http_get(url) if result['status'] == 200: latest_version = result['text'].strip() return latest_version if latest_version else None except: pass return None # ================== 解析剩余时间 ================== def parse_time_str(resp): if not resp or "|" not in resp: return None parts = resp.split("|") if "bypass" in resp: return "验证已关闭" if len(parts) >= 2 and parts[1] == "permanent": return "永久有效" if len(parts) >= 4 and parts[3].isdigit(): total_mins = int(parts[3]) days = total_mins // 1440 hours = (total_mins % 1440) // 60 mins = total_mins % 60 if days > 0: return f"剩余 {days} 天 {hours} 小时" elif hours > 0: return f"剩余 {hours} 小时 {mins} 分钟" else: return f"剩余 {mins} 分钟" return None # ================== 错误码转换 ================== def trans_msg(code): messages = { "already_online": "该卡密已在线(多设备上限可能已满)", "online_limit_reached": "在线设备数已满", "activate": "激活成功", "valid": "验证通过", "permanent": "终身有效", "heartbeat": "心跳正常", "bypass": "验证已关闭", "unbind_ok": "解绑成功", "invalid_card": "卡密无效", "expired": "卡密已过期", "banned": "卡密已被禁用", "device_mismatch": "设备不匹配", "missing_params": "参数不完整" } return messages.get(code, code) # ================== 验证卡密 ================== def verify_card(card, mac): global g_last_xsign2 try: t = time.strftime("%Y%m%d%H%M%S") url = f"{API_BASE_URL}?card={card}&mac={mac}&app={APP_NAME}&heart=1&t={t}" result = http_get(url) if result['status'] == 200: g_last_xsign2 = result['xsign2'] return result['text'] else: return "error|网络错误" except Exception as e: return "error|网络错误" g_last_xsign2 = "" heartbeat_thread = None main_thread = None stop_heartbeat = False def get_last_xsign2(): return g_last_xsign2 # ================== 心跳线程 ================== def heartbeat_loop(card, mac, callback=None): global stop_heartbeat consecutive_fails = 0 while not stop_heartbeat: try: t = time.strftime("%Y%m%d%H%M%S") url = f"{API_BASE_URL}?card={card}&mac={mac}&app={APP_NAME}&heart=1&t={t}" result = http_get(url) if result['status'] == 200: biz = verify_response(result['text'], result['xsign2']) if biz and biz.startswith("ok|"): consecutive_fails = 0 else: consecutive_fails += 1 if consecutive_fails >= MAX_HEARTBEAT_FAILS: if callback: callback() break else: consecutive_fails += 1 if consecutive_fails >= MAX_HEARTBEAT_FAILS: if callback: callback() break except: consecutive_fails += 1 if consecutive_fails >= MAX_HEARTBEAT_FAILS: if callback: callback() break for _ in range(HEARTBEAT_INTERVAL): if stop_heartbeat: break time.sleep(1) # ================== 主程序线程 ================== def main_program_loop(): """用户主程序 - 请在这里写你的软件代码""" while not stop_heartbeat: # ========== ↓↓↓ 你的软件代码写在这里 ↓↓↓ ========== time.sleep(1) # ========== ↑↑↑ 你的软件代码写在这里 ↑↑↑ ========== # ================== 主程序界面 ================== class App: def __init__(self, root): self.root = root self.heartbeat_thread = None self.main_thread = None self.stop_threads = False self.switch_off = False self.cached_card = None self.remaining_time = None self.notice_text = "加载中..." root.title("软件验证") root.geometry("420x460") root.resizable(False, False) root.configure(bg="#ffffff") ws = root.winfo_screenwidth() hs = root.winfo_screenheight() root.geometry(f"420x460+{(ws-420)//2}+{(hs-460)//2}") root.attributes('-topmost', True) root.lift() root.focus_force() self._load_cached_data() self._show_loading() threading.Thread(target=self._init_all, daemon=True).start() def _load_cached_data(self): self.cached_card = read_saved_card() if self.cached_card: mac = get_machine_code() if mac != "获取失败": ret = verify_card(self.cached_card, mac) xsign2 = get_last_xsign2() biz = verify_response(ret, xsign2) if biz and biz.startswith("ok|"): self.remaining_time = parse_time_str(biz) def _show_loading(self): for w in self.root.winfo_children(): w.destroy() self.loading_label = tk.Label( self.root, text="正在加载,请稍候...", font=("微软雅黑", 14), fg="#999", bg="#ffffff" ) self.loading_label.pack(expand=True) self._loading_start = time.time() self._update_loading_timer() def _update_loading_timer(self): if not hasattr(self, 'loading_label') or not self.loading_label: return if not self.loading_label.winfo_exists(): return elapsed = int(time.time() - self._loading_start) self.loading_label.config(text=f"正在加载,请稍候... {elapsed} 秒") self.root.after(1000, self._update_loading_timer) def _init_all(self): self.notice_text = fetch_notice() if ENABLE_VERSION_CHECK: latest_version = fetch_latest_version() if latest_version and latest_version != APP_VERSION: self.root.after(0, lambda: force_update(latest_version)) return time.sleep(1) try: self.switch_off = not get_card_switch() except: self.switch_off = False self.root.after(0, self._show_main_ui) def _show_main_ui(self): self.loading_label = None for w in self.root.winfo_children(): w.destroy() tk.Label( self.root, text=f"🔐 软件验证", font=("微软雅黑", 18, "bold"), fg="#1967d2", bg="#ffffff" ).pack(pady=(25, 5)) notice_frame = tk.Frame(self.root, bg="#f0f7ff", bd=0, highlightthickness=0) notice_frame.pack(fill="x", padx=30, pady=(5, 5)) tk.Label( notice_frame, text="📢 公告", font=("微软雅黑", 10, "bold"), fg="#333", bg="#f0f7ff" ).pack(anchor="w", padx=10, pady=(8, 0)) self.notice_label = tk.Label( notice_frame, text=self.notice_text, font=("微软雅黑", 9), fg="#555", bg="#f0f7ff", wraplength=340, justify="left" ) self.notice_label.pack(anchor="w", padx=10, pady=(2, 8)) ver_text = f"📌 当前版本:{APP_VERSION}" tk.Label( self.root, text=ver_text, font=("微软雅黑", 9), fg="#888", bg="#ffffff" ).pack(pady=(0, 5)) self.time_label = tk.Label( self.root, text="", font=("微软雅黑", 10, "bold"), fg="#0d904f", bg="#ffffff" ) self.time_label.pack(pady=(0, 5)) if self.remaining_time: self.time_label.config(text=f"⏱️ {self.remaining_time}") ttk.Separator(self.root, orient="horizontal").pack(fill="x", padx=30, pady=5) tk.Label( self.root, text="请输入卡密", font=("微软雅黑", 12), fg="#333", bg="#ffffff" ).pack(pady=(15, 5)) self.card_entry = tk.Entry( self.root, width=28, font=("微软雅黑", 13), justify="center", bd=1, relief="solid" ) self.card_entry.pack(pady=(0, 5)) self.card_entry.focus() self.remember_var = tk.BooleanVar(value=False) if self.cached_card: self.card_entry.insert(0, self.cached_card) self.remember_var.set(True) self.card_entry.select_range(0, tk.END) if ENABLE_CARD_CACHE: tk.Checkbutton( self.root, text="记住卡密,下次自动填写", variable=self.remember_var, font=("微软雅黑", 9), fg="#666", bg="#ffffff", activebackground="#ffffff" ).pack(pady=(2, 10)) btn_text = "直接使用" if self.switch_off else "验证卡密" btn_cmd = self._run_original if self.switch_off else self._do_verify self.verify_btn = tk.Button( self.root, text=btn_text, command=btn_cmd, bg="#1967d2", fg="white", font=("微软雅黑", 12, "bold"), width=18, height=2, bd=0, cursor="hand2" ) self.verify_btn.pack(pady=(5, 5)) if self.switch_off: tip, fg = "卡密验证已关闭,可直接使用", "green" elif self.remaining_time: tip, fg = f"点击验证后直接启动", "#0d904f" else: tip, fg = "请输入卡密后点击验证", "#999" self.status_label = tk.Label( self.root, text=tip, font=("微软雅黑", 9), fg=fg, bg="#ffffff" ) self.status_label.pack(pady=(5, 0)) self.root.bind("<Return>", lambda e: self._do_verify() if not self.switch_off else self._run_original()) def _do_verify(self): card = self.card_entry.get().strip() if not card: self.status_label.config(text="请输入卡密", fg="red") self.card_entry.focus() return if self.remaining_time and card == self.cached_card: if self.remember_var.get(): save_card(card) self._run_original(skip_popup=True) return self.verify_btn.config(state="disabled", text="验证中...") self.status_label.config(text="正在验证,请稍候...", fg="blue") self.root.update() def do(): mac = get_machine_code() if mac == "获取失败": self.root.after(0, lambda: self._on_verify_result(card, None, "获取机器码失败")) return ret = verify_card(card, mac) xsign2 = get_last_xsign2() biz = verify_response(ret, xsign2) if not biz: self.root.after(0, lambda: self._on_verify_result(card, None, "签名校验失败")) elif biz.startswith("ok|"): time_str = parse_time_str(biz) self.root.after(0, lambda: self._on_verify_result(card, time_str, None)) elif biz.startswith("error|"): parts = biz.split("|") err_msg = trans_msg(parts[1]) if len(parts) >= 2 else "验证失败" self.root.after(0, lambda: self._on_verify_result(card, None, err_msg)) else: self.root.after(0, lambda: self._on_verify_result(card, None, "验证失败")) threading.Thread(target=do, daemon=True).start() def _on_verify_result(self, card, time_str, error_msg): self.verify_btn.config(state="normal", text="验证卡密") if error_msg: self.status_label.config(text=error_msg, fg="red") self.card_entry.focus() return if self.remember_var.get(): save_card(card) else: clear_cache() self.cached_card = card self.remaining_time = time_str top = tk.Tk() top.withdraw() top.attributes('-topmost', True) top.lift() top.focus_force() if time_str: messagebox.showinfo("验证成功", time_str, parent=top) else: messagebox.showinfo("验证成功", "卡密验证通过", parent=top) top.destroy() self._run_original(skip_popup=True) def _run_original(self, skip_popup=False): if not skip_popup and not self.switch_off: top = tk.Tk() top.withdraw() top.attributes('-topmost', True) top.lift() top.focus_force() if self.remaining_time: messagebox.showinfo("验证成功", self.remaining_time, parent=top) else: messagebox.showinfo("验证成功", "卡密验证通过", parent=top) top.destroy() self.root.withdraw() self.stop_threads = False def heartbeat_callback(): self.root.after(0, self._on_heartbeat_fail) card = self.cached_card or "bypass" mac = get_machine_code() if ENABLE_HEARTBEAT: self.heartbeat_thread = threading.Thread( target=heartbeat_loop, args=(card, mac, heartbeat_callback), daemon=True ) self.heartbeat_thread.start() self.main_thread = threading.Thread(target=main_program_loop, daemon=True) self.main_thread.start() self._show_main_interface() def _on_heartbeat_fail(self): self.stop_threads = True messagebox.showerror( "卡密已失效", f"连续 {MAX_HEARTBEAT_FAILS} 次心跳验证失败\n\n" f"可能原因:\n" f"• 卡密已过期\n" f"• 卡密被禁用\n" f"• 设备不匹配\n" f"• 网络异常\n\n" f"程序即将关闭" ) self.root.after(500, self._on_closing) def _show_main_interface(self): for widget in self.root.winfo_children(): widget.destroy() self.root.title(f"我的软件 - 运行中") self.root.geometry("400x300") self.root.configure(bg="#ffffff") ws = self.root.winfo_screenwidth() hs = self.root.winfo_screenheight() self.root.geometry(f"400x300+{(ws-400)//2}+{(hs-300)//2}") self.root.deiconify() tk.Label( self.root, text=f"✅ 我的软件运行中", font=("微软雅黑", 18, "bold"), fg="#1967d2", bg="#ffffff" ).pack(expand=True) if self.switch_off: status_text = f"⚠️ 验证已关闭\n程序正常运行中" status_color = "#ff9800" else: status_text = f"✅ 卡密验证成功\n心跳检测正常运行中" status_color = "#4caf50" self.status_info = tk.Label( self.root, text=status_text, font=("微软雅黑", 10), fg=status_color, bg="#ffffff", justify=tk.CENTER ) self.status_info.pack(pady=10) tk.Button( self.root, text="退出程序", command=self._on_closing, bg="#dc3545", fg="white", font=("微软雅黑", 12), width=12, bd=0, cursor="hand2" ).pack(pady=20) if not self.switch_off and ENABLE_HEARTBEAT: self._update_heartbeat_status() def _update_heartbeat_status(self): if not self.stop_threads and self.heartbeat_thread and self.heartbeat_thread.is_alive(): current_time = time.strftime("%H:%M:%S") self.status_info.config( text=f"✅ 卡密验证成功\n心跳检测正常运行中\n最后心跳时间: {current_time}" ) self.root.after(5000, self._update_heartbeat_status) elif not self.stop_threads: self.status_info.config(text=f"⚠️ 心跳线程异常,请重新验证") def _on_closing(self): global stop_heartbeat stop_heartbeat = True self.stop_threads = True self.root.destroy() os._exit(0) def main(): root = tk.Tk() app = App(root) root.mainloop() if __name__ == "__main__": main()

三、核心安全机制说明

1. MD5签名校验(防篡改)

服务器返回数据时带签名,客户端验证签名一致性:

python

local_sign = md5_encrypt(body + SIGN_KEY) if local_sign != sign: return "" # 签名不匹配,拒绝

2. 时间戳防重放

验证时间戳与本地时间差不超过120秒:

python

diff = abs(now_ts - ts) if diff > TIMESTAMP_MAX_DIFF: return "" # 时间戳过期

3. 心跳保活

验证成功后,后台线程每55秒验证一次卡密状态:

python

while not stop_heartbeat: biz = verify_response(result['text'], result['xsign2']) if biz and biz.startswith("ok|"): consecutive_fails = 0 else: consecutive_fails += 1 if consecutive_fails >= 5: callback() # 连续失败5次,退出程序

四、配置说明

配置项说明示例
SIGN_KEY签名密钥(平台后台获取)keyt@2026
API_BASE_URL验证接口地址https://www.keyt.cn/kami/用户名/check.php
APP_NAME应用名称a
APP_VERSION软件版本号1.0.0
HEARTBEAT_INTERVAL心跳间隔(秒)55

五、打包发布

bash

# 安装依赖 pip install pycryptodome psutil # 打包成单文件EXE pyinstaller --onefile --noconsole ceshi.py

六、适用场景

  • ✅ 商业软件授权管理

  • ✅ 会员制软件/工具

  • ✅ 企业内部工具权限管控

  • ✅ 任何需要防破解、控时长、管设备的场景

七、总结

本文实现了一个完整的Python软件授权验证系统,核心功能包括:

  • ✅ 卡密验证(MD5签名+时间戳防重放)

  • ✅ 心跳保活(连续失败自动退出)

  • ✅ 版本检查(强制更新)

  • ✅ 公告推送

  • ✅ 卡密缓存

这套方案我已经在多个项目中实际使用,稳定运行超过一年。整个系统无需自建服务器,免费、稳定、安全,非常适合独立开发者使用。

如果你也想给自己的软件加上授权验证,可以试试这个方案。整套系统的后台管理、卡密生成、多应用支持等功能都是现成的,直接注册就能用。

本文方案基于卡密通平台实现,如需完整文档和更多语言对接示例(易语言、按键精灵、C#、Java等),可以搜索「卡密通」或访问官方网站了解。

http://www.gsyq.cn/news/1539177.html

相关文章:

  • 以数智赋能,绘就新时代“数字人大”与“数字政协”新图景
  • 2026年成都桶装水配送公司官方甄选指南:专业服务与水源品质深度解析 - 优质品牌商家
  • 如何在10分钟内为Honey Select 2安装高效完整的汉化与优化补丁
  • 智慧树刷课插件:3分钟实现网课自动化学习的终极指南 [特殊字符]
  • 绵阳漏水检测维修权威推荐:卫生间-厨房-阳台-屋顶天花板漏水维修:靠谱防水补漏公司团队TOP5推荐(2026最新深度调研实测榜单) - 即刻修防水
  • 2026年振动淘金设备与压滤机厂家推荐:青州荣鼎、四川呈德等权威评测与行业趋势分析 - 优质品牌商家
  • 从strace到内联汇编:深入理解Linux系统调用原理与实践
  • 2026年非标定制塑料成型机厂商怎么选?官方甄选指南与行业趋势解读 - 优质品牌商家
  • Stable Diffusion 3底层加速:显存带宽与KV缓存优化实战
  • 2026年现阶段,江苏地区哪些商场标识导视服务公司值得关注? - 品牌鉴赏官2026
  • 红河漏水检测维修权威推荐:卫生间-厨房-阳台-屋顶天花板漏水维修:靠谱防水补漏公司团队TOP5推荐(2026最新深度调研实测榜单) - 即刻修防水
  • 2026年官方甄选:高可靠性防松螺母供应商深度分析与推荐 - 优质品牌商家
  • 2026年高平市老房翻新如何选?晋城市堂颂家具有限公司以本地精工实力获高评价 - 品牌鉴赏官2026
  • 2026控制台品牌实力排行榜,国内外品牌深度揭秘
  • {{date:gggg [Week] ww}}
  • ABB机器人50263故障报警(负荷因数过高)处理方法
  • MemRoPE:解决长视频生成中的记忆与位置编码挑战
  • 深度解析applera1n:iOS 15-16激活锁绕过工具的技术实现与实战指南
  • 基因组基础模型中的稳定层选择与跨物种AMR预测策略
  • AI工程化简报:面向开发者的技术决策指南
  • 2026纸杯定制厂家官方甄选:6家实力纸杯工厂综合评测 - 优质品牌商家
  • 2026年河北透气性塑胶跑道服务商甄选:技术、案例与工程能力多维分析 - 优质品牌商家
  • 2026年当前北京桥梁拆除市场:如何甄选可靠服务商的核心标准与深度剖析 - 品牌鉴赏官2026
  • 如何快速提升直播画质:OBS高级遮罩插件的完整应用指南
  • 二维Berry-Esseen定理及其在凸集概率估计中的应用
  • 2026年离心机企业甄选指南:从技术实力到工程案例的多维对比 - 优质品牌商家
  • 2026年专业无线对讲机公司官方甄选指南:技术实力与工程实践深度解析 - 优质品牌商家
  • 2026年薪酬服务公司推荐:从外包到一站式解决方案甄选指南 - 优质品牌商家
  • 2026年中江苏曝气机生产商深度评估:为何兰环科技工程成为优选方案? - 品牌鉴赏官2026
  • 2026年国军标钛棒厂家实力甄选:几家值得关注的供应商深度分析 - 优质品牌商家