谁来帮我修一下bug?
本帖最后由 歌者文明清理员 于 2023-7-17 15:00 编辑补充:对不起,搞错了,内容已更新
问题是为什么使用“testuser”做用户名,密码是“abcdABCDAB”的时候提示“用户已存在”?
通过admin tool 可以看见,但还是搞不懂怎么回事
import os
import string
from ttkbootstrap import *
from tkinter import Text, Button
from pickle import load, dump
from threading import Thread
from time import sleep
PATH_DATA = os.path.join(os.path.dirname(__file__), "data")
PATH_USERS = os.path.join(PATH_DATA, "users.fishc")
(
CODE_SUCCESS,
CODE_NOT_FOUND,
CODE_DUPLICATE,
CODE_WRONG_PARAMETER,
CODE_LENGTH_ERROR,
CODE_WEAK_PASSWORD
) = range(6)
SAFE_LOWEST, SAFE_1, SAFE_2, SAFE_3, SAFE_HIGHEST = range(5)
def check_dir(path):
"""
检查一个目录是否存在,如果不存在就创建一个
:param path: 路径
:return: None
"""
if not os.path.isdir(path):
os.mkdir(path)
def check_file(path, binary=False, default=""):
"""
检查一个文件是否存在,如果不存在就创建一个
:param path: 路径
:param binary: 是否为二进制文件
:param default: 如果此文件为空,默认值
:return: none
"""
if not os.path.isfile(path):
if binary:
with open(path, "wb") as f:
dump(default, f)
else:
with open(path, "w") as f:
f.write(default)
check_dir(PATH_DATA)
check_file(PATH_USERS, True, [])
class User:
def __init__(self, username, password):
"""
创建一个用户
:param username: 用户名
:param password: 密码
"""
self.username = username
self.password = password
def info(self):
"""
获取某人的 info
:return: info `(username, password)`
"""
return self.username, self.password
def add_user(username, password):
"""
将一个用户添加到 `data/users.fishc`
:param username: 用户名
:param password: 密码
:return: 被添加的用户
"""
user = User(username, password)
data = get_userlist()
data.append(user)
write_into_userlist(data)
return user
def remove_user(username, password):
"""
从用户列表移除一个用户(data/users.fishc)
:param username: 用户名
:param password: 密码
:return: 被删除的用户
"""
data = get_userlist()
index = None
for i, (user, pwd) in enumerate(map(User.info, data)):
if user == username:
if pwd == password:
index = i
break
else:
raise ValueError("wrong password")
else:
raise ValueError("wrong username")
data.pop(index)
write_into_userlist(data)
def get_userlist():
"""
获取用户列表(data/users.fishc)
:return: 用户列表
"""
with open(PATH_USERS, "rb") as f:
data = load(f)
return data
def write_into_userlist(data):
"""
将内容写入用户列表(data/users.fishc)
:param data: 新内容
:return: None
"""
with open(PATH_USERS, "wb") as f:
dump(data, f)
def login(username, password):
"""
登录进一个账号
:param username: 用户名
:param password: 密码
:return: (状态码, 找到的用户)
"""
users = get_userlist()
# 为了便于判断,用 for 循环
for user in users:
if user.info() == (username, password):
# 登录成功
return (CODE_SUCCESS, user)
return (CODE_NOT_FOUND, None)
def register(username, password):
"""
注册一个用户
:param username: 用户名
:param password: 密码
:return: (状态码, 新用户)
"""
# 检查用户名是否已被使用
users =
if username in users:
return (CODE_DUPLICATE, None)
if username == "Admin":
return (CODE_SUCCESS, add_user(username, password))
if not 3 <= len(username) < 11:
return (CODE_LENGTH_ERROR, None)
# 密码强度
password_strength = check_password_strength(password)
# 必须达到 SAFE_3 级别
if password_strength < SAFE_3:
if password_strength == SAFE_LOWEST:
show_message(label_password_weak0)
elif password_strength == SAFE_1:
show_message(label_password_weak1)
elif password_strength == SAFE_2:
show_message(label_password_weak2)
# 创建用户
return (CODE_SUCCESS, add_user(username, password))
def command_login():
"""
作为 button 的 `command` 属性的函数,用于调用 `login()`
:return: None
"""
value_username = entry_username.get()
value_password = entry_password.get()
status = login(value_username, value_password)
if status == CODE_SUCCESS:
show_message(label_message2)
frame_login.place_forget()
else:
show_message(label_message1)
def command_register():
"""
作为 button 的 `command` 属性的函数,用于调用 `register()`
:return: None
"""
value_username = entry_username.get()
value_password = entry_password.get()
status = register(value_username, value_password)
if status == CODE_SUCCESS:
show_message(label_message3)
elif status == CODE_DUPLICATE:
show_message(label_message4)
elif status == CODE_LENGTH_ERROR:
show_message(label_message5)
def disappear(obj, method, time1, time2):
"""
使某个控件在几秒后消失。(打字机特效,指定秒数少一个字符)
注意,请使用 `threading.Thread` 调用此函数,否则会造成窗口卡死。
:param obj: 控件
:param method: 控件使用的方法,为“place”、“pack”、“grid”中的一种
:param time1: 过多久才开始消失
:param time2: 消失的时间,多久消失一个字
:return: 状态码
"""
# 先提前搞到文字,到时候消失了要放回去
text = obj["text"]
# 等待
sleep(time1)
while obj["text"]:
# 减少一个字
obj["text"] = obj["text"][:-1]
sleep(time2)
obj["text"] = text
# 使控件消失
getattr(obj, f"{method}_forget")()
def show_message(obj):
"""
显示一条消息
:param obj: 消息对象(`Label`)
:return: None
"""
obj.place(**temp3)
Thread(target=disappear, args=(obj, "place", 1, 0.1)).start()
def check_password_strength(pwd):
"""
检查密码的安全级别。规则如下:
| 判断条件 | 判断结果 | 返回值 |
|:-----------------------------|:---------|:---------------|
| 密码长度 < 10 | 不安全 | `SAFE_LOWEST`|
| 密码只含有数字 | 不太安全 | `SAFE_1` |
| 密码只有字母 | 中等 | `SAFE_2` |
| 密码有字母和数字 | 有点安全 | `SAFE_3` |
| 密码有数字、大小写字母和符号 | 安全 | `SAFE_HIGHEST` |
:param pwd: 密码
:return: 参考表格
"""
if len(pwd) < 10:
return SAFE_LOWEST
number = False
lowercase = False
uppercase = False
punctuation = False
for char in pwd:
# 避免二次判断
if not number and char in string.digits:
number = True
if not lowercase and char in string.ascii_lowercase:
lowercase = True
if not uppercase and char in string.ascii_uppercase:
uppercase = True
if not punctuation and char in string.punctuation:
punctuation = True
result = (number, lowercase, uppercase, punctuation)
result_count = result.count(True)
if number and result_count == 1:
# 只有数字
return SAFE_1
if (lowercase or uppercase) and 1 <= result_count < 3:
# 只有字母
return SAFE_2
if (lowercase or uppercase) and number and 2 <= result_count < 4:
# 大/小写字母且有数字
return SAFE_3
if lowercase and uppercase and number and punctuation:
return SAFE_HIGHEST
def change_password_visiblity():
"""
切换密码输入框的可见性,如果密码没隐藏则隐藏,如果隐藏了就不隐藏
:return: None
"""
if entry_password["show"] == "":
# 密码没有隐藏
entry_password["show"] = "*"
button_change_password_visiblity["text"] = "显示密码"
else:
# 密码隐藏了
entry_password["show"] = ""
button_change_password_visiblity["text"] = "隐藏密码"
def change_admin_tool_visiblity():
"""
切换 Admin Tool 的可见性
:return: None
"""
if bool(frame_admin_tool.winfo_manager()):
frame_admin_tool.place_forget()
# 没隐藏
button_admin_tool["text"] = "打开 Admin Tool"
else:
frame_admin_tool.place(relx=0.9, rely=0.2, anchor="ne")
# 隐藏了
button_admin_tool["text"] = "关闭 Admin Tool"
def change_users_visiblity():
"""
管理用户(Admin Tool)
:return: None
"""
# 以防万一
text_users.delete(0.0, END)
if bool(text_users.winfo_manager()):
button_show_userlist["text"] = "显示用户列表"
text_users.grid_forget()
else:
button_show_userlist["text"] = "隐藏用户列表"
text_users.grid(row=1, column=0, **temp2)
text_users.insert(END, '\n'.join([' '.join(user.info()) for user in get_userlist()]))
temp1 = {"padx": 10, "pady": 10}
temp2 = {"padx": 5, "pady": 5}
temp3 = {"relx": 0.8, "rely": 0.2, "anchor": "ne"}
bootstyle = {
"primary": {"fg": "white", "bg": "#4582ec"},
"secondary": {"fg": "white", "bg": "#adb5db"},
"success": {"fg": "white", "bg": "#02b875"},
"info": {"fg": "white", "bg": "#17a2b8"},
"warning": {"fg": "white", "bg": "#f0ad4e"},
"danger": {"fg": "white", "bg": "#d9534f"},
"light": {"fg": "black", "bg": "#f8f9fa"},
"dark": {"fg": "white", "bg": "#343a40"}
}
root = Window("This Forum 1.0 Beta 测试版本 - By dddddgz", "morph")
root.geometry("1000x800+100+100")
label_message1 = Label(root, bootstyle="danger", text="密码或用户名错误")
label_message2 = Label(root, bootstyle="success", text="登录成功!")
label_message3 = Label(root, bootstyle="success", text="注册成功!")
label_message4 = Label(root, bootstyle="danger", text="用户名已存在")
label_message5 = Label(root, bootstyle="danger", text="用户名字符数限制:3-10")
label_password_weak0 = Label(root, bootstyle="danger", text="密码太弱,没有达到10个字符")
label_password_weak1 = Label(root, bootstyle="danger", text="密码只有数字")
label_password_weak2 = Label(root, bootstyle="danger", text="密码只有大写或小写字母")
frame_login = Frame(root)
label_username = Label(frame_login, bootstyle="dark", text="用户名")
label_username.grid(row=0, column=0, **temp1, columnspan=2)
entry_username = Entry(frame_login, bootstyle="info", width=30)
entry_username.grid(row=1, column=0, **temp1, columnspan=2)
label_password = Label(frame_login, bootstyle="dark", text="密码")
label_password.grid(row=2, column=0, **temp1, columnspan=2)
entry_password = Entry(frame_login, bootstyle="primary", width=30)
entry_password.grid(row=3, column=0, **temp1, columnspan=2)
button_change_password_visiblity = Button(frame_login, **bootstyle["primary"])
button_change_password_visiblity["command"] = change_password_visiblity
button_change_password_visiblity.grid(row=3, column=2, **temp1)
change_password_visiblity()
button_login = Button(frame_login)
button_login["text"] = "登录"
button_login["width"] = 8
button_login["command"] = command_login
button_login.grid(row=4, column=0, **temp1)
button_register = Button(frame_login)
button_register["text"] = "注册"
button_register["width"] = 8
button_register["command"] = command_register
button_register.grid(row=4, column=1, **temp1)
frame_login.place(relx=0.5, rely=0.5, anchor="center")
button_admin_tool = Button(root, **bootstyle["info"])
button_admin_tool["text"] = "打开 Admin Tool"
button_admin_tool["command"] = change_admin_tool_visiblity
button_admin_tool.place(relx=0.8, rely=0.9, anchor="ne")
frame_admin_tool = Frame(root)
button_show_userlist = Button(frame_admin_tool, **bootstyle["warning"])
button_show_userlist["text"] = "查看用户列表"
button_show_userlist["command"] = change_users_visiblity
button_show_userlist.grid(row=0, column=0, **temp2)
text_users = Text(frame_admin_tool, width=10, height=10)
root.mainloop()
根据你提供的代码,我看到在注册用户时会检查用户名是否已存在。如果使用"testuser"作为用户名,密码是"1111111111"时提示"用户已存在",这是因为在第80行检查用户名是否已被使用时,程序发现"testuser"已经存在于用户列表中,所以返回了状态码CODE_DUPLICATE,表示用户名已存在。你可以更改用户名或选择一个不存在的用户名进行测试。 @isdkz @sfqxx @liuhongrun2022 没明白你的意思 liuhongrun2022 发表于 2023-7-19 12:51
没明白你的意思
问题是为什么使用“testuser”做用户名,密码是“abcdABCDAB”的时候提示“用户已存在”? 非常抱歉,但是我只能处理最多2048个字数token的请求。您提供的内容超过了我的处理能力,请缩短您的输入并重新提交问题,我将尽力回答。谢谢!
您的代码看上去非常整洁,但是在您的 "register" 函数中,您没有正确地返回密码强度检查的结果。当前的代码只有当密码强度达到 SAFE_3 或更高级别时,才会注册新用户,但是,如果密码强度低于 SAFE_3,函数并未返回任何状态码。这可能是您遇到“用户已存在”提示的原因。
您的 "register" 函数可以修改如下:
def register(username, password):
"""
注册一个用户
:param username: 用户名
:param password: 密码
:return: (状态码, 新用户)
"""
# 检查用户名是否已被使用
users =
if username in users:
return (CODE_DUPLICATE, None)
if username == "Admin":
return (CODE_SUCCESS, add_user(username, password))
if not 3 <= len(username) < 11:
return (CODE_LENGTH_ERROR, None)
# 密码强度
password_strength = check_password_strength(password)
# 必须达到 SAFE_3 级别
if password_strength < SAFE_3:
if password_strength == SAFE_LOWEST:
show_message(label_password_weak0)
return (CODE_WEAK_PASSWORD, None)
elif password_strength == SAFE_1:
show_message(label_password_weak1)
return (CODE_WEAK_PASSWORD, None)
elif password_strength == SAFE_2:
show_message(label_password_weak2)
return (CODE_WEAK_PASSWORD, None)
# 创建用户
return (CODE_SUCCESS, add_user(username, password))
这样,在密码强度低于 SAFE_3 时,该函数就会返回一个状态码(CODE_WEAK_PASSWORD),并显示相应的消息。这可能解决了您的问题。
此外,我注意到代码中没有具体的 "Admin Tool",您提到的 "Admin Tool" 是另一个模块或者是界面部分吗?如果是,请确保在使用该工具添加或修改用户时,遵循同样的用户名和密码要求。
我希望这能解决您的问题。如果还有其他问题或细节需要了解,请随时告诉我! isdkz 发表于 2023-7-19 12:59
您的代码看上去非常整洁,但是在您的 "register" 函数中,您没有正确地返回密码强度检查的结果。当前的代码 ...
谢,问题确实解决了,可是command register里我并没有检查返回值为none的情况啊 歌者文明清理员 发表于 2023-7-19 13:09
谢,问题确实解决了,可是command register里我并没有检查返回值为none的情况啊
Python中,当函数没有明确返回值的时候,默认返回的是None。如果你在使用command register并且没有考虑到返回None的情况,可能会在使用返回结果的时候遇到问题。
比如说,如果你试图对一个None值进行某种操作(如索引,迭代或者调用方法等)的话,Python会抛出一个TypeError。
这就是为什么在处理command register的返回值之前,我们通常会检查它是否为None。如果为None,那么我们可以根据具体情况来决定下一步的操作,比如抛出一个错误,返回一个默认值,或者跳过后续的操作。
以下是一个例子:
result = command_register(args)
if result is None:
print("Command not found!")
else:
# 处理正常的结果
在这个例子中,如果command_register返回None(也就是说,没有找到与给定参数匹配的命令),我们会打印一个错误信息,然后跳过后续的处理。如果找到了匹配的命令,我们就继续正常的处理。 哇歌者你这代码写的漂亮啊{:10_275:}
https://xxx.ilovefishc.com/forum/202307/17/161432nbtt5wj5m5rmetoe.gif
页:
[1]