用Python和Tkinter标准模块建立密码管理器

news2025/1/27 4:23:09

用Python和Tkinter标准模块建立密码管理器

创建一个简单的密码管理器应用程序,帮助用户存储和管理他们的密码。使用Python的tkinter模块来创建一个图形用户界面(GUI)。

本程序支持 添加、查看、搜索、复制、修改、删除 功能。

本程序使用 SQLite建立 passwords.db用以保存密码信息。

通过强制所有密码相关操作以字符串形式处理,解决前导零丢失问题。

Base64是Python的标准库模块之一,用于进行Base64编码和解码操作。Base64并不是一种加密算法,而是一种编码方案,它不适合用于保护敏感信息,在此用于简化演示。如果需要保护敏感信息(如密码),应使用真正的加密算法(如 AES)。

运行效果:

源码如下:

import tkinter as tk
from tkinter import ttk, messagebox
import sqlite3
import base64

# 加密函数(强制输入为字符串)
def encrypt(password):
    password_str = str(password)  # 强制转为字符串
    return base64.b64encode(password_str.encode()).decode()

# 解密函数(直接返回字符串)
def decrypt(encrypted_password):
    decrypted_bytes = base64.b64decode(encrypted_password.encode())
    return decrypted_bytes.decode()  # 直接返回字符串

# 初始化数据库
def init_db():
    conn = sqlite3.connect("passwords.db")
    cursor = conn.cursor()
    cursor.execute("""
        CREATE TABLE IF NOT EXISTS passwords (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            project TEXT NOT NULL,
            username TEXT NOT NULL,
            password TEXT NOT NULL
        )
    """)
    conn.commit()
    conn.close()

# 添加密码(强制密码为字符串)
def add_password():
    project = project_entry.get()
    username = username_entry.get()
    password = password_entry.get()

    if not project or not username or not password:
        messagebox.showwarning("输入错误", "请填写所有字段!")
        return

    encrypted_password = encrypt(str(password))  # 强制转为字符串

    conn = sqlite3.connect("passwords.db")
    cursor = conn.cursor()
    cursor.execute("INSERT INTO passwords (project, username, password) VALUES (?, ?, ?)",
                   (project, username, encrypted_password))
    conn.commit()
    conn.close()

    project_entry.delete(0, tk.END)
    username_entry.delete(0, tk.END)
    password_entry.delete(0, tk.END)
    view_passwords()

# 查看密码(显示时强制转为字符串)
def view_passwords():
    for row in tree.get_children():
        tree.delete(row)

    conn = sqlite3.connect("passwords.db")
    cursor = conn.cursor()
    cursor.execute("SELECT id, project, username, password FROM passwords")
    rows = cursor.fetchall()
    conn.close()

    for row in rows:
        id, project, username, encrypted_password = row
        decrypted_password = decrypt(encrypted_password)
        tree.insert("", tk.END, values=(id, project, username, str(decrypted_password)))

# 搜索密码
def search_password():
    search_term = search_entry.get()

    for row in tree.get_children():
        tree.delete(row)

    conn = sqlite3.connect("passwords.db")
    cursor = conn.cursor()
    cursor.execute("SELECT id, project, username, password FROM passwords WHERE project LIKE ?",
                   (f"%{search_term}%",))
    rows = cursor.fetchall()
    conn.close()

    for row in rows:
        id, project, username, encrypted_password = row
        decrypted_password = decrypt(encrypted_password)
        tree.insert("", tk.END, values=(id, project, username, str(decrypted_password)))

# 复制密码(关键修复:直接从数据库获取)
def copy_password():
    selected_item = tree.selection()
    if not selected_item:
        messagebox.showwarning("未选择", "请选择一条记录!")
        return

    # 获取选中行的项目名和用户名
    item = tree.item(selected_item)
    project = item["values"][1]
    username = item["values"][2]

    # 直接从数据库查询原始密码
    conn = sqlite3.connect("passwords.db")
    cursor = conn.cursor()
    cursor.execute("SELECT password FROM passwords WHERE project = ? AND username = ?", (project, username))
    row = cursor.fetchone()
    conn.close()

    if row:
        encrypted_password = row[0]
        decrypted_password = decrypt(encrypted_password)
        root.clipboard_clear()
        root.clipboard_append(str(decrypted_password))  # 强制转为字符串
        messagebox.showinfo("复制成功", "密码已复制到剪贴板!")
    else:
        messagebox.showerror("错误", "未找到密码!")

# 删除记录
def delete_password():
    selected_item = tree.selection()
    if not selected_item:
        messagebox.showwarning("未选择", "请选择一条记录!")
        return

    item = tree.item(selected_item)
    record_id = item["values"][0]

    confirm = messagebox.askyesno("确认删除", "确定要删除这条记录吗?")
    if not confirm:
        return

    conn = sqlite3.connect("passwords.db")
    cursor = conn.cursor()
    cursor.execute("DELETE FROM passwords WHERE id = ?", (record_id,))
    conn.commit()
    conn.close()

    view_passwords()

# 修改记录(关键修复:输入框获取值强制为字符串)
def edit_password():
    selected_item = tree.selection()
    if not selected_item:
        messagebox.showwarning("未选择", "请选择一条记录!")
        return

    item = tree.item(selected_item)
    record_id = item["values"][0]

    # 直接从数据库获取原始密码
    conn = sqlite3.connect("passwords.db")
    cursor = conn.cursor()
    cursor.execute("SELECT project, username, password FROM passwords WHERE id = ?", (record_id,))
    project, username, encrypted_password = cursor.fetchone()
    conn.close()
    current_password = decrypt(encrypted_password)

    edit_window = tk.Toplevel(root)
    edit_window.title("修改记录")
    edit_window.geometry("300x200")

    # 项目名
    ttk.Label(edit_window, text="项目名:").grid(row=0, column=0, padx=5, pady=5)
    project_entry = ttk.Entry(edit_window, width=25)
    project_entry.grid(row=0, column=1, padx=5, pady=5)
    project_entry.insert(0, project)

    # 用户名
    ttk.Label(edit_window, text="用户名:").grid(row=1, column=0, padx=5, pady=5)
    username_entry = ttk.Entry(edit_window, width=25)
    username_entry.grid(row=1, column=1, padx=5, pady=5)
    username_entry.insert(0, username)

    # 密码(关键:输入框直接使用字符串,避免转换)
    ttk.Label(edit_window, text="密码:").grid(row=2, column=0, padx=5, pady=5)
    password_entry = ttk.Entry(edit_window, width=25)
    password_entry.grid(row=2, column=1, padx=5, pady=5)
    password_entry.insert(0, str(current_password))  # 强制转为字符串

    def save_edit():
        new_project = project_entry.get()
        new_username = username_entry.get()
        new_password = password_entry.get()  # 直接获取字符串

        if not new_project or not new_username or not new_password:
            messagebox.showwarning("输入错误", "请填写所有字段!")
            return

        encrypted_password = encrypt(str(new_password))  # 加密前确保为字符串

        conn = sqlite3.connect("passwords.db")
        cursor = conn.cursor()
        cursor.execute("""
            UPDATE passwords 
            SET project = ?, username = ?, password = ?
            WHERE id = ?
        """, (new_project, new_username, encrypted_password, record_id))
        conn.commit()
        conn.close()

        messagebox.showinfo("成功", "记录已更新!")
        edit_window.destroy()
        view_passwords()

    save_button = ttk.Button(edit_window, text="保存", command=save_edit)
    save_button.grid(row=3, column=0, columnspan=2, pady=10)

# 初始化数据库
init_db()

# 创建主窗口
root = tk.Tk()
root.title("密码管理器")
root.geometry("800x600")

# 输入区域
input_frame = ttk.LabelFrame(root, text="添加密码")
input_frame.pack(fill=tk.X, padx=10, pady=10)

ttk.Label(input_frame, text="项目名:").grid(row=0, column=0, padx=5, pady=5)
project_entry = ttk.Entry(input_frame, width=30)
project_entry.grid(row=0, column=1, padx=5, pady=5)

ttk.Label(input_frame, text="用户名:").grid(row=1, column=0, padx=5, pady=5)
username_entry = ttk.Entry(input_frame, width=30)
username_entry.grid(row=1, column=1, padx=5, pady=5)

ttk.Label(input_frame, text="密码:").grid(row=2, column=0, padx=5, pady=5)
password_entry = ttk.Entry(input_frame, width=30)
password_entry.grid(row=2, column=1, padx=5, pady=5)

add_button = ttk.Button(input_frame, text="添加", command=add_password)
add_button.grid(row=3, column=0, columnspan=2, pady=10)

# 搜索区域
search_frame = ttk.LabelFrame(root, text="搜索密码")
search_frame.pack(fill=tk.X, padx=10, pady=10)

ttk.Label(search_frame, text="搜索项目名:").grid(row=0, column=0, padx=5, pady=5)
search_entry = ttk.Entry(search_frame, width=30)
search_entry.grid(row=0, column=1, padx=5, pady=5)

search_button = ttk.Button(search_frame, text="搜索", command=search_password)
search_button.grid(row=0, column=2, padx=5, pady=5)

show_all_button = ttk.Button(search_frame, text="全部显示", command=view_passwords)
show_all_button.grid(row=0, column=3, padx=5, pady=5)

# 密码列表
tree_frame = ttk.LabelFrame(root, text="密码列表")
tree_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

columns = ("id", "project", "username", "password")
tree = ttk.Treeview(tree_frame, columns=columns, show="headings")
tree.heading("project", text="项目名")
tree.heading("username", text="用户名")
tree.heading("password", text="密码")
tree.column("id", width=0, stretch=tk.NO)  # 隐藏ID列
tree.column("password", width=150)
tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

# 操作按钮区域
button_frame = ttk.Frame(tree_frame)
button_frame.pack(pady=10)

copy_button = ttk.Button(button_frame, text="复制密码", command=copy_password)
copy_button.pack(side=tk.LEFT, padx=5)

edit_button = ttk.Button(button_frame, text="修改记录", command=edit_password)
edit_button.pack(side=tk.LEFT, padx=5)

delete_button = ttk.Button(button_frame, text="删除记录", command=delete_password)
delete_button.pack(side=tk.LEFT, padx=5)

# 首次加载显示数据
view_passwords()

# 运行主循环
root.mainloop()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2283187.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

day1代码练习

输出3-100以内的完美数&#xff0c;(完美数&#xff1a;因子和(因子不包含自身)数本身) #include <stdio.h>// 判断一个数是否为完美数的函数 int panduan(int n) {if (n < 2) {return 0; // 小于2的数不可能是完美数}int sum 1; // 因子和初始化为1&#xff08;因…

为什么redis会开小差?Redis 频繁异常的深度剖析与解决方案

文章目录 导读为什么redis会开小差&#xff1f;1.连接数过多2.bigkey3.慢命令操作4.内存策略不合理5.外部数据双写一致性6.保护机制未开启7. 数据集中过期8. CPU饱和9. 持久化阻塞10. 网络问题结论 导读 提起分布式缓存&#xff0c;想必大多数同学脑海中都会浮出redis这个名字…

C# Interlocked 类使用详解

总目录 前言 在多线程编程中&#xff0c;确保多个线程对共享资源的安全访问是一个关键挑战。C# 提供了多种同步机制来处理并发问题&#xff0c;其中 System.Threading.Interlocked 类提供了一种轻量级的方法来进行原子操作。它允许您执行一些常见的增量、减量、交换等操作&…

VS Code i18n国际化组件代码code显示中文配置 i18n ally

VUE项目做i18n国际化之后&#xff0c;代码中的中文都变成了code这时的代码就会显得非常难读&#xff0c;如果有一个插件能把code转换成中文显示就好了 vscode插件搜索“i18n ally” 在项目根文件夹下创建文件&#xff1a;.vscode/settings.json settings.json 内容如下 {"…

MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log

文章目录 一、前言1.1 MySQL体系结构1.2 MySQL日志分类1.3 其他几种日志1.3.1 查询日志1.3.2 慢查询日志1.3.3 错误日志 二、bin log 二进制日志2.1 bin log简介2.2 binlog日志格式2.3 日志删除2.4 写入/刷盘机制 三、undo log 回滚日志3.1 undo log简介3.2 隐藏字段 —— 事务…

一文速通stack和queue的理解与使用

CSTL之stack和queue 1.stack1.1.stack的基本概念1.2.stack的接口 2.queue2.1.queue的基本概念2.2.queue的接口 3.priority_queue3.1.priority_queue的基本概念3.2.priority_queue的接口3.3.仿函数 4.容器适配器5.deque5.1.deque的简单了解5.2.deque的优缺点 &#x1f31f;&…

关于CAN(FD)转以太网详细介绍

一、功能描述 CANFD 完全向下兼容 CAN &#xff0c;以下统称 CAN(FD) 。 SG-CAN(FD)NET-210 是一款用来把 CANFD 总线数据转为网口数据的设备。 网口支持 TCP Sever 、 TCP Client 、 UDP Sever 、 UDP Client 四种模式。 可以通过软件配置和 Web 网页配置。 两路…

orbbec 奥比中光相机单目及多目调用方式python代码

这篇文章会介绍使用orbbec相机的一些常用代码梯子 orbbec 奥比中光Astra相机单目及多目调用方式编译sdk调用单相机调用多相机orbbec 奥比中光Astra相机单目及多目调用方式 Orbbec相机是一个专注于深度感知和计算机视觉应用的设备,通常用于3D扫描、手势识别、增强现实(AR)以及…

力扣hot100-->滑动窗口、贪心

你好呀&#xff0c;欢迎来到 Dong雨 的技术小栈 &#x1f331; 在这里&#xff0c;我们一同探索代码的奥秘&#xff0c;感受技术的魅力 ✨。 &#x1f449; 我的小世界&#xff1a;Dong雨 &#x1f4cc; 分享我的学习旅程 &#x1f6e0;️ 提供贴心的实用工具 &#x1f4a1; 记…

PBFT算法

在我的博客中对于RAFT算法也有详细的介绍&#xff0c;raft算法包含三种角色&#xff0c;分别是&#xff1a;跟随者&#xff08; follower &#xff09;&#xff0c;候选人&#xff08;candidate &#xff09;和领导者&#xff08; leader &#xff09;。集群中的一个节点在某一…

跨境电商代购系统独立站深度分享

在全球化日益加深的今天&#xff0c;跨境电商代购系统独立站作为一种新兴的电子商务模式&#xff0c;正逐渐成为连接全球消费者与优质商品的重要桥梁。本文将详细介绍跨境电商代购系统独立站的基本功能以及技术实现的重难点&#xff0c;以期为相关从业者提供一些有价值的参考和…

携程旅行 登录分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 所有加密流程基本一样就说…

西藏酥油茶:高原上的醇香温暖

西藏酥油茶:高原上的醇香温暖 在西藏高原,有一种饮品,它不仅滋养了一代又一代的藏民,还承载着丰富的文化与历史,它就是西藏酥油茶。酥油茶,藏语称为“恰苏玛”,意为搅动的茶,是藏族人民日常生活中不可或缺的一部分,更是待客、祭祀等活动中的重要礼仪物品。 历史与文化渊源 酥…

刷题总结 回溯算法

为了方便复习并且在把算法忘掉的时候能尽量快速的捡起来 刷完回溯算法这里需要做个总结 回溯算法的适用范围 回溯算法是深度优先搜索&#xff08;DFS&#xff09;的一种特定应用&#xff0c;在DFS的基础上引入了约束检查和回退机制。 相比于普通的DFS&#xff0c;回溯法的优…

Antd React Form使用Radio嵌套多个Select和Input的处理

使用Antd React Form使用Radio会遇到嵌套多个Select和Input的处理&#xff0c;需要多层嵌套和处理默认事件和冒泡&#xff0c;具体实现过程直接上代码。 实现效果布局如下图 代码 <Formname"basic"form{form}labelWrap{...formItemLayoutSpan(5, 19)}onFinish{on…

Linux(Centos、Ubuntu) 系统安装jenkins服务

该文章手把手演示在Linux系统下如何安装jenkins服务、并自定义jenkins数据文件位置、以及jenkins如何设置国内镜像源加速&#xff0c;解决插件下载失败问题 安装方式&#xff1a;war包安装 阿里云提供的war下载源地址&#xff1a;https://mirrors.aliyun.com/jenkins/war/?s…

【基于无线电的数据通信链】Link 11 仿真测试

〇、废话 Link 11 仿真测试 涉及多个方面&#xff0c;包括信号仿真、协议模拟、数据链路层的仿真以及网络性能评估等。Link 11 是一种基于 HF&#xff08;高频&#xff09; 或 UHF&#xff08;超高频&#xff09; 波段的无线通信协议&#xff0c;主要用于军事通信系统中。为了…

VScode 开发 Springboot 程序

1. 通过maven创建springboot程序 输入 mvn archetype:generate 选择模板&#xff0c;一般默认选择为第 7 种方式&#xff1b; 选择之后&#xff0c;一般要你填写如下内容&#xff1a; groupId: 组织名称&#xff1b;artifactId: 项目名称&#xff1b;version: 版本&#xff0…

深入MapReduce——引入

引入 前面我们已经深入了HDFS的设计与实现&#xff0c;对于分布式系统也有了不错的理解。 但HDFS仅仅解决了海量数据存储和读写的问题。要想让数据产生价值&#xff0c;一定是需要从数据中挖掘出价值才行&#xff0c;这就需要我们拥有海量数据的计算处理能力。 下面我们还是…

springfox-swagger-ui 3.0.0 配置

在3.0中&#xff0c;访问地址URL变了。 http://地址:端口/项目名/swagger-ui/ SpringBoot maven项目引入 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>3.0.0</version> </…