乐于分享
好东西不私藏

Tkinter教程45:给软件添加一机一码,登入授权验证(hashlib+hmac+到期时间)

Tkinter教程45:给软件添加一机一码,登入授权验证(hashlib+hmac+到期时间)

Python,速成心法

敲代码,查资料,问度娘

练习,探索,总结,优化

博文创作不易,源码使用过程中,如有疑问的地方,欢迎大家指正留言交流。喜欢的老铁可以多多点赞+收藏分享+置顶,小红牛在此表示感谢。

-------★Tkinter系列教程★--------

Tkinter教程44:对Canvas表格姓名和工资整列,做样式标记

Tkinter教程43:root.after定时器函数的示例用法

Tkinter教程42:复制treeview表格,选中的行内容

Tkinter教程41:ttk.Treeview带指示符(▲/▼)的表格排序示例

Tkinter教程40:(鼠标,键盘等)事件处理综合示例

Tkinter教程39:常用tk组件综合示例,3分钟带你速学速成,安排 !!

Tkinter教程37:Treeview 中可用的内置图标有哪些?

Tkinter教程34:绘制高级Canvas表格(高亮颜色标记+排序+编辑功能)

Tkinter教程31:各种对话框示例演示

Tkinter教程30:4种登入界面样例,你喜欢哪个?

Tkinter教程29:组件自适应窗口大小的布局方法

Tkinter教程28:ttk.Style()有哪些内置的主题样式?

Python项目28:设计日志管理系统2.0(Tkinter+Json)

Tkinter教程27:tkcalendar制作日期框组件

Tkinter教程26:Text组件绑定Scrollbar滚动条+font设置字体属性+复制粘贴,撤销恢复操作

Tkinter教程25:Text控件中,文本存在某个关键字的将被高亮显示(标记颜色+字体加粗)

Tkinter教程24:4种布局管理控件,Frame框架+LabelFrame标签+PanedWindow窗格+Toplevel

Tkinter教程23:Entry输入框+Label标签+Text文本框的示例用法

Tkinter教程22:DataFrame数据加入到treeview树视图(含横纵滚动条+正反向排序)

Tkinter教程21:Listbox列表框+OptionMenu选项菜单+Combobox下拉列表框控件的使用+绑定事件

Tkinter教程20:treeview树视图组件,表格数据的插入与表头排序

Python教程57:tkinter中如何执行,单击按钮的单线程操作

Python教程56:tkinter中如何隐藏/去掉最大化窗口

教你使用Pyinstaller将Python源码打包成可执行程序exe的方法

经典游戏04:给老板写一封拒绝不了的辞职信

Python源码:Tkinter组件布局管理的3种方式

Python源码:关于Tkinter需要学习的知识点

Python项目源码06:简单计算器源码1.0(tkinter)

1.生成授权码的源码(供授权方使用):授权方需要获取用户的机器码+使用相同密钥计算签名。

# -*- coding: utf-8 -*-# @Author : 小红牛# 微信公众号:wdPythonimport tkinter as tkfrom tkinter import ttk, messageboximport jsonimport hmacimport hashlibimport osimport uuidimport platformimport subprocess# ==================== 固定密钥 ====================SECRET_KEY = b"wdpython2026_key888"# ==================== 机器码生成 ====================def get_machine_code():    mac = uuid.getnode()    mac_str = '{:012x}'.format(mac).upper()    disk_serial = ""    if platform.system() == "Windows":        try:            cmd = "wmic diskdrive get SerialNumber"            result = subprocess.run(cmd, shell=True, capture_output=True, text=True)            lines = [line.strip() for line in result.stdout.splitlines() if line.strip()]            if len(lines) > 1:                disk_serial = lines[1].strip()        except:            pass    raw = f"68{mac_str}60{disk_serial}30{platform.node()}"    return hashlib.sha256(raw.encode()).hexdigest()[:32]def generate_license(username, expire):    if not username or not expire:        return None    message = f"{username}{expire}".encode('utf-8')    sign = hmac.new(SECRET_KEY, message, hashlib.sha256).hexdigest()    return {"username": username, "expire": expire, "sign": sign}# ==================== GUI ====================class LicenseGeneratorApp:    def __init__(self, master):        self.master = master        master.title("授权码生成器")        master.geometry("500x240")        master.resizable(FalseFalse)        # 居中        master.update_idletasks()        w, h = master.winfo_width(), master.winfo_height()        x = (master.winfo_screenwidth() // 2) - (w // 2)        y = (master.winfo_screenheight() // 2) - (h // 2)        master.geometry(f"+{x}+{y}")        # 主框架(pack 布局)        main_frame = ttk.Frame(master, padding=20)        main_frame.pack(fill=tk.BOTH, expand=True)        # ---- 机器码行 ----        row1 = ttk.Frame(main_frame)        row1.pack(fill=tk.X, pady=5)        ttk.Label(row1, text="用户机器码(32位):").pack(side=tk.LEFT)        self.username_entry = ttk.Entry(row1, width=40)        self.username_entry.pack(side=tk.LEFT, padx=5)        # ---- 过期日期行 ----        row2 = ttk.Frame(main_frame)        row2.pack(fill=tk.X, pady=5)        ttk.Label(row2, text="过期日期(YYYYMMDD):").pack(side=tk.LEFT)        self.expire_entry = ttk.Entry(row2, width=36)        self.expire_entry.pack(side=tk.LEFT, padx=5)        self.expire_entry.insert(0"20261231")        # ---- 提示 ----        ttk.Label(main_frame, text="提示:日期格式为 8 位数字,如 20261231", foreground="gray").pack(anchor="w", pady=5)        # ---- 按钮 ----        btn_frame = ttk.Frame(main_frame)        btn_frame.pack(pady=15)        ttk.Button(btn_frame, text="生成授权码", command=self.generate, width=15).pack(side=tk.LEFT, padx=15)        ttk.Button(btn_frame, text="刷新机器码", command=self.read_machine_code, width=10).pack(side=tk.LEFT, padx=5)        # ---- 状态栏 ----        self.status_var = tk.StringVar()        self.status_var.set("就绪")        ttk.Label(main_frame, textvariable=self.status_var, foreground="blue").pack(anchor="w", pady=10)        # 启动自动读取        self.read_machine_code()    def read_machine_code(self):        code = get_machine_code()        self.username_entry.delete(0, tk.END)        self.username_entry.insert(0, code)        self.status_var.set(f"已读取机器码:{code}")    def generate(self):        username = self.username_entry.get().strip()        expire = self.expire_entry.get().strip()        if not username:            messagebox.showerror("错误""请先获取机器码")            return        if len(username) != 32:            messagebox.showerror("错误""机器码应为32位字符")            return        if not expire.isdigit() or len(expire) != 8:            messagebox.showerror("错误""日期必须为8位数字(YYYYMMDD)")            return        lic_data = generate_license(username, expire)        if not lic_data:            messagebox.showerror("错误""生成授权数据失败")            return        # 直接写入当前目录(脚本所在目录)        file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "授权码.json")        try:            with open(file_path, 'w', encoding='utf-8'as f:                json.dump(lic_data, f, indent=2, ensure_ascii=False)            self.status_var.set(f"✅ 授权文件已生成:{file_path}")            messagebox.showinfo("成功"f"授权文件已保存至:\n{file_path}")        except Exception as e:            messagebox.showerror("保存失败"f"写入文件时出错:{e}")            self.status_var.set("保存失败")if __name__ == "__main__":    root = tk.Tk()    app = LicenseGeneratorApp(root)    root.mainloop()

2.登入验证源码:软件里面增加登入系统验证,判断授权码的是否正确正确就可以登入软件,不正确就不能使用软件。如下所示

当前机器码: dfdeede544ea7faa5bcb64602c73e174
正在验证授权...
✅ 授权验证成功!到期时间:2026-12-31
# -*- coding: utf-8 -*-"""授权验证图形化示例(无登录窗口)功能:启动后直接验证授权,弹出新窗口显示结果依赖:tkinter(内置)"""import osimport jsonimport hashlibimport hmacimport uuidimport platformimport subprocessfrom datetime import datetimeimport tkinter as tk# ------------------- 授权核心 -------------------SECRET_KEY = b"wdpython2026_key888"def get_machine_code():    """生成机器码(32位十六进制)"""    mac = uuid.getnode()    mac_str = '{:012x}'.format(mac).upper()    disk_serial = ""    if platform.system() == "Windows":        try:            cmd = "wmic diskdrive get SerialNumber"            result = subprocess.run(cmd, shell=True, capture_output=True, text=True)            lines = [line.strip() for line in result.stdout.splitlines() if line.strip()]            if len(lines) > 1:                disk_serial = lines[1].strip()        except:            pass    raw = f"68{mac_str}60{disk_serial}30{platform.node()}"    machine_code = hashlib.sha256(raw.encode()).hexdigest()[:32]    return machine_codedef verify_license(license_path="授权码.json"):    """验证授权文件,返回(是否有效, 过期日期或None)"""    if not os.path.exists(license_path):        return FalseNone    try:        with open(license_path, 'r', encoding='utf-8'as f:            lic = json.load(f)        username = lic.get("username")        expire = lic.get("expire")        sign = lic.get("sign")        if not all([username, expire, sign]):            return FalseNone        if username != get_machine_code():            return FalseNone        today = datetime.now().strftime("%Y%m%d")        if expire < today:            return False, expire        message = f"{username}{expire}".encode('utf-8')        expected_sign = hmac.new(SECRET_KEY, message, hashlib.sha256).hexdigest()        if hmac.compare_digest(expected_sign, sign):            return True, expire        else:            return FalseNone    except Exception:        return FalseNone# ------------------- 授权结果窗口 -------------------class AuthWindow:    """授权验证结果窗口"""    def __init__(self):        self.win = tk.Tk()        self.win.title("授权验证")        self.win.geometry("450x280")        self.win.resizable(FalseFalse)        # 显示机器码        machine = get_machine_code()        tk.Label(self.win, text=f"机器码: {machine}", font=("Arial"10)).pack(pady=10)        # 执行验证        success, expire = verify_license()        if success:            expire_display = f"{expire[:4]}-{expire[4:6]}-{expire[6:8]}"            status = f"✅ 授权有效\n到期时间: {expire_display}"            color = "green"        else:            if expire:                expire_display = f"{expire[:4]}-{expire[4:6]}-{expire[6:8]}"                status = f"❌ 授权已过期\n到期日: {expire_display}"            else:                status = "❌ 授权验证失败\n可能原因:授权文件不存在、机器码不匹配或签名无效。"            color = "red"        # 显示结果        label_status = tk.Label(self.win, text=status, font=("Arial"12), fg=color, justify="left")        label_status.pack(pady=20)        # 退出按钮        btn_quit = tk.Button(self.win, text="退出", command=self.win.destroy, width=10)        btn_quit.pack(pady=20)        self.win.mainloop()# ------------------- 启动入口 -------------------if __name__ == "__main__":    AuthWindow()

完毕!!感谢您的收看

--------★历史博文集合★--------

Python入门篇  进阶篇  视频教程  Py安装

py项目Python模块 Python爬虫  Json

Xpath正则表达式SeleniumEtreeCss

Gui程序开发TkinterPyqt5 列表元组字典

数据可视化 matplotlib词云图Pyecharts

海龟画图PandasBug处理电脑小知识

自动化脚本编程工具NumPy CSVWeb

Pygame  图像处理    机器学习数据库