鱼C论坛

 找回密码
 立即注册
查看: 1823|回复: 9

[已解决]谁来帮我修一下bug?

[复制链接]
发表于 2023-7-17 14:57:26 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 歌者文明清理员 于 2023-7-17 15:00 编辑

补充:对不起,搞错了,内容已更新

问题是为什么使用“testuser”做用户名,密码是“abcdABCDAB”的时候提示“用户已存在”?

通过admin tool 可以看见,但还是搞不懂怎么回事

  1. import os
  2. import string
  3. from ttkbootstrap import *
  4. from tkinter import Text, Button
  5. from pickle import load, dump
  6. from threading import Thread
  7. from time import sleep

  8. PATH_DATA = os.path.join(os.path.dirname(__file__), "data")
  9. PATH_USERS = os.path.join(PATH_DATA, "users.fishc")

  10. (
  11.     CODE_SUCCESS,
  12.     CODE_NOT_FOUND,
  13.     CODE_DUPLICATE,
  14.     CODE_WRONG_PARAMETER,
  15.     CODE_LENGTH_ERROR,
  16.     CODE_WEAK_PASSWORD
  17. ) = range(6)

  18. SAFE_LOWEST, SAFE_1, SAFE_2, SAFE_3, SAFE_HIGHEST = range(5)

  19. def check_dir(path):
  20.     """
  21.     检查一个目录是否存在,如果不存在就创建一个
  22.     :param path: 路径
  23.     :return: None
  24.     """
  25.     if not os.path.isdir(path):
  26.         os.mkdir(path)

  27. def check_file(path, binary=False, default=""):
  28.     """
  29.     检查一个文件是否存在,如果不存在就创建一个
  30.     :param path: 路径
  31.     :param binary: 是否为二进制文件
  32.     :param default: 如果此文件为空,默认值
  33.     :return: none
  34.     """
  35.     if not os.path.isfile(path):
  36.         if binary:
  37.             with open(path, "wb") as f:
  38.                 dump(default, f)
  39.         else:
  40.             with open(path, "w") as f:
  41.                 f.write(default)

  42. check_dir(PATH_DATA)
  43. check_file(PATH_USERS, True, [])

  44. class User:
  45.     def __init__(self, username, password):
  46.         """
  47.         创建一个用户
  48.         :param username: 用户名
  49.         :param password: 密码
  50.         """
  51.         self.username = username
  52.         self.password = password
  53.    
  54.     def info(self):
  55.         """
  56.         获取某人的 info
  57.         :return: info `(username, password)`
  58.         """
  59.         return self.username, self.password

  60. def add_user(username, password):
  61.     """
  62.     将一个用户添加到 `data/users.fishc`
  63.     :param username: 用户名
  64.     :param password: 密码
  65.     :return: 被添加的用户
  66.     """
  67.     user = User(username, password)
  68.     data = get_userlist()
  69.     data.append(user)
  70.     write_into_userlist(data)
  71.     return user

  72. def remove_user(username, password):
  73.     """
  74.     从用户列表移除一个用户(data/users.fishc)
  75.     :param username: 用户名
  76.     :param password: 密码
  77.     :return: 被删除的用户
  78.     """
  79.     data = get_userlist()
  80.     index = None
  81.     for i, (user, pwd) in enumerate(map(User.info, data)):
  82.         if user == username:
  83.             if pwd == password:
  84.                 index = i
  85.                 break
  86.             else:
  87.                 raise ValueError("wrong password")
  88.     else:
  89.         raise ValueError("wrong username")
  90.     data.pop(index)
  91.     write_into_userlist(data)

  92. def get_userlist():
  93.     """
  94.     获取用户列表(data/users.fishc)
  95.     :return: 用户列表 [User(username, password), ...]
  96.     """
  97.     with open(PATH_USERS, "rb") as f:
  98.         data = load(f)
  99.     return data

  100. def write_into_userlist(data):
  101.     """
  102.     将内容写入用户列表(data/users.fishc)
  103.     :param data: 新内容
  104.     :return: None
  105.     """
  106.     with open(PATH_USERS, "wb") as f:
  107.         dump(data, f)

  108. def login(username, password):
  109.     """
  110.     登录进一个账号
  111.     :param username: 用户名
  112.     :param password: 密码
  113.     :return: (状态码, 找到的用户)
  114.     """
  115.     users = get_userlist()
  116.     # 为了便于判断,用 for 循环
  117.     for user in users:
  118.         if user.info() == (username, password):
  119.             # 登录成功
  120.             return (CODE_SUCCESS, user)
  121.     return (CODE_NOT_FOUND, None)

  122. def register(username, password):
  123.     """
  124.     注册一个用户
  125.     :param username: 用户名
  126.     :param password: 密码
  127.     :return: (状态码, 新用户)
  128.     """
  129.     # 检查用户名是否已被使用
  130.     users = [user.username for user in get_userlist()]
  131.     if username in users:
  132.         return (CODE_DUPLICATE, None)
  133.     if username == "Admin":
  134.         return (CODE_SUCCESS, add_user(username, password))
  135.     if not 3 <= len(username) < 11:
  136.         return (CODE_LENGTH_ERROR, None)
  137.     # 密码强度
  138.     password_strength = check_password_strength(password)
  139.     # 必须达到 SAFE_3 级别
  140.     if password_strength < SAFE_3:
  141.         if password_strength == SAFE_LOWEST:
  142.             show_message(label_password_weak0)
  143.         elif password_strength == SAFE_1:
  144.             show_message(label_password_weak1)
  145.         elif password_strength == SAFE_2:
  146.             show_message(label_password_weak2)
  147.         
  148.     # 创建用户
  149.     return (CODE_SUCCESS, add_user(username, password))

  150. def command_login():
  151.     """
  152.     作为 button 的 `command` 属性的函数,用于调用 `login()`
  153.     :return: None
  154.     """
  155.     value_username = entry_username.get()
  156.     value_password = entry_password.get()
  157.     status = login(value_username, value_password)[0]
  158.     if status == CODE_SUCCESS:
  159.         show_message(label_message2)
  160.         frame_login.place_forget()
  161.     else:
  162.         show_message(label_message1)

  163. def command_register():
  164.     """
  165.     作为 button 的 `command` 属性的函数,用于调用 `register()`
  166.     :return: None
  167.     """
  168.     value_username = entry_username.get()
  169.     value_password = entry_password.get()
  170.     status = register(value_username, value_password)[0]
  171.     if status == CODE_SUCCESS:
  172.         show_message(label_message3)
  173.     elif status == CODE_DUPLICATE:
  174.         show_message(label_message4)
  175.     elif status == CODE_LENGTH_ERROR:
  176.         show_message(label_message5)

  177. def disappear(obj, method, time1, time2):
  178.     """
  179.     使某个控件在几秒后消失。(打字机特效,指定秒数少一个字符)

  180.     注意,请使用 `threading.Thread` 调用此函数,否则会造成窗口卡死。
  181.     :param obj: 控件
  182.     :param method: 控件使用的方法,为“place”、“pack”、“grid”中的一种
  183.     :param time1: 过多久才开始消失
  184.     :param time2: 消失的时间,多久消失一个字
  185.     :return: 状态码
  186.     """
  187.     # 先提前搞到文字,到时候消失了要放回去
  188.     text = obj["text"]
  189.     # 等待
  190.     sleep(time1)
  191.     while obj["text"]:
  192.         # 减少一个字
  193.         obj["text"] = obj["text"][:-1]
  194.         sleep(time2)
  195.     obj["text"] = text
  196.     # 使控件消失
  197.     getattr(obj, f"{method}_forget")()

  198. def show_message(obj):
  199.     """
  200.     显示一条消息
  201.     :param obj: 消息对象(`Label`)
  202.     :return: None
  203.     """
  204.     obj.place(**temp3)
  205.     Thread(target=disappear, args=(obj, "place", 1, 0.1)).start()

  206. def check_password_strength(pwd):
  207.     """
  208.     检查密码的安全级别。规则如下:

  209.     |             判断条件         | 判断结果 |    返回值      |
  210.     |:-----------------------------|:---------|:---------------|
  211.     | 密码长度 < 10                | 不安全   | `SAFE_LOWEST`  |
  212.     | 密码只含有数字               | 不太安全 | `SAFE_1`       |
  213.     | 密码只有字母                 | 中等     | `SAFE_2`       |
  214.     | 密码有字母和数字             | 有点安全 | `SAFE_3`       |
  215.     | 密码有数字、大小写字母和符号 | 安全     | `SAFE_HIGHEST` |

  216.     :param pwd: 密码
  217.     :return: 参考表格
  218.     """
  219.     if len(pwd) < 10:
  220.         return SAFE_LOWEST
  221.     number = False
  222.     lowercase = False
  223.     uppercase = False
  224.     punctuation = False
  225.     for char in pwd:
  226.         # 避免二次判断
  227.         if not number and char in string.digits:
  228.             number = True
  229.         if not lowercase and char in string.ascii_lowercase:
  230.             lowercase = True
  231.         if not uppercase and char in string.ascii_uppercase:
  232.             uppercase = True
  233.         if not punctuation and char in string.punctuation:
  234.             punctuation = True
  235.     result = (number, lowercase, uppercase, punctuation)
  236.     result_count = result.count(True)
  237.     if number and result_count == 1:
  238.         # 只有数字
  239.         return SAFE_1
  240.     if (lowercase or uppercase) and 1 <= result_count < 3:
  241.         # 只有字母
  242.         return SAFE_2
  243.     if (lowercase or uppercase) and number and 2 <= result_count < 4:
  244.         # 大/小写字母且有数字
  245.         return SAFE_3
  246.     if lowercase and uppercase and number and punctuation:
  247.         return SAFE_HIGHEST

  248. def change_password_visiblity():
  249.     """
  250.     切换密码输入框的可见性,如果密码没隐藏则隐藏,如果隐藏了就不隐藏
  251.     :return: None
  252.     """
  253.     if entry_password["show"] == "":
  254.         # 密码没有隐藏
  255.         entry_password["show"] = "*"
  256.         button_change_password_visiblity["text"] = "显示密码"
  257.     else:
  258.         # 密码隐藏了
  259.         entry_password["show"] = ""
  260.         button_change_password_visiblity["text"] = "隐藏密码"

  261. def change_admin_tool_visiblity():
  262.     """
  263.     切换 Admin Tool 的可见性
  264.     :return: None
  265.     """
  266.     if bool(frame_admin_tool.winfo_manager()):
  267.         frame_admin_tool.place_forget()
  268.         # 没隐藏
  269.         button_admin_tool["text"] = "打开 Admin Tool"
  270.     else:
  271.         frame_admin_tool.place(relx=0.9, rely=0.2, anchor="ne")
  272.         # 隐藏了
  273.         button_admin_tool["text"] = "关闭 Admin Tool"

  274. def change_users_visiblity():
  275.     """
  276.     管理用户(Admin Tool)
  277.     :return: None
  278.     """
  279.     # 以防万一
  280.     text_users.delete(0.0, END)
  281.     if bool(text_users.winfo_manager()):
  282.         button_show_userlist["text"] = "显示用户列表"
  283.         text_users.grid_forget()
  284.     else:
  285.         button_show_userlist["text"] = "隐藏用户列表"
  286.         text_users.grid(row=1, column=0, **temp2)
  287.         text_users.insert(END, '\n'.join([' '.join(user.info()) for user in get_userlist()]))

  288. temp1 = {"padx": 10, "pady": 10}
  289. temp2 = {"padx": 5, "pady": 5}
  290. temp3 = {"relx": 0.8, "rely": 0.2, "anchor": "ne"}

  291. bootstyle = {
  292.     "primary":   {"fg": "white", "bg": "#4582ec"},
  293.     "secondary": {"fg": "white", "bg": "#adb5db"},
  294.     "success":   {"fg": "white", "bg": "#02b875"},
  295.     "info":      {"fg": "white", "bg": "#17a2b8"},
  296.     "warning":   {"fg": "white", "bg": "#f0ad4e"},
  297.     "danger":    {"fg": "white", "bg": "#d9534f"},
  298.     "light":     {"fg": "black", "bg": "#f8f9fa"},
  299.     "dark":      {"fg": "white", "bg": "#343a40"}
  300. }

  301. root = Window("This Forum 1.0 Beta 测试版本 - By dddddgz", "morph")
  302. root.geometry("1000x800+100+100")

  303. label_message1 = Label(root, bootstyle="danger", text="密码或用户名错误")
  304. label_message2 = Label(root, bootstyle="success", text="登录成功!")
  305. label_message3 = Label(root, bootstyle="success", text="注册成功!")
  306. label_message4 = Label(root, bootstyle="danger", text="用户名已存在")
  307. label_message5 = Label(root, bootstyle="danger", text="用户名字符数限制:3-10")

  308. label_password_weak0 = Label(root, bootstyle="danger", text="密码太弱,没有达到10个字符")
  309. label_password_weak1 = Label(root, bootstyle="danger", text="密码只有数字")
  310. label_password_weak2 = Label(root, bootstyle="danger", text="密码只有大写或小写字母")

  311. frame_login = Frame(root)

  312. label_username = Label(frame_login, bootstyle="dark", text="用户名")
  313. label_username.grid(row=0, column=0, **temp1, columnspan=2)
  314. entry_username = Entry(frame_login, bootstyle="info", width=30)
  315. entry_username.grid(row=1, column=0, **temp1, columnspan=2)

  316. label_password = Label(frame_login, bootstyle="dark", text="密码")
  317. label_password.grid(row=2, column=0, **temp1, columnspan=2)
  318. entry_password = Entry(frame_login, bootstyle="primary", width=30)
  319. entry_password.grid(row=3, column=0, **temp1, columnspan=2)

  320. button_change_password_visiblity = Button(frame_login, **bootstyle["primary"])
  321. button_change_password_visiblity["command"] = change_password_visiblity
  322. button_change_password_visiblity.grid(row=3, column=2, **temp1)
  323. change_password_visiblity()

  324. button_login = Button(frame_login)
  325. button_login["text"] = "登录"
  326. button_login["width"] = 8
  327. button_login["command"] = command_login
  328. button_login.grid(row=4, column=0, **temp1)

  329. button_register = Button(frame_login)
  330. button_register["text"] = "注册"
  331. button_register["width"] = 8
  332. button_register["command"] = command_register
  333. button_register.grid(row=4, column=1, **temp1)

  334. frame_login.place(relx=0.5, rely=0.5, anchor="center")

  335. button_admin_tool = Button(root, **bootstyle["info"])
  336. button_admin_tool["text"] = "打开 Admin Tool"
  337. button_admin_tool["command"] = change_admin_tool_visiblity
  338. button_admin_tool.place(relx=0.8, rely=0.9, anchor="ne")

  339. frame_admin_tool = Frame(root)

  340. button_show_userlist = Button(frame_admin_tool, **bootstyle["warning"])
  341. button_show_userlist["text"] = "查看用户列表"
  342. button_show_userlist["command"] = change_users_visiblity
  343. button_show_userlist.grid(row=0, column=0, **temp2)

  344. text_users = Text(frame_admin_tool, width=10, height=10)

  345. root.mainloop()
复制代码
最佳答案
2023-7-19 12:59:33
您的代码看上去非常整洁,但是在您的 "register" 函数中,您没有正确地返回密码强度检查的结果。当前的代码只有当密码强度达到 SAFE_3 或更高级别时,才会注册新用户,但是,如果密码强度低于 SAFE_3,函数并未返回任何状态码。这可能是您遇到“用户已存在”提示的原因。

您的 "register" 函数可以修改如下:

  1. def register(username, password):
  2.     """
  3.     注册一个用户
  4.     :param username: 用户名
  5.     :param password: 密码
  6.     :return: (状态码, 新用户)
  7.     """
  8.     # 检查用户名是否已被使用
  9.     users = [user.username for user in get_userlist()]
  10.     if username in users:
  11.         return (CODE_DUPLICATE, None)
  12.     if username == "Admin":
  13.         return (CODE_SUCCESS, add_user(username, password))
  14.     if not 3 <= len(username) < 11:
  15.         return (CODE_LENGTH_ERROR, None)
  16.     # 密码强度
  17.     password_strength = check_password_strength(password)
  18.     # 必须达到 SAFE_3 级别
  19.     if password_strength < SAFE_3:
  20.         if password_strength == SAFE_LOWEST:
  21.             show_message(label_password_weak0)
  22.             return (CODE_WEAK_PASSWORD, None)
  23.         elif password_strength == SAFE_1:
  24.             show_message(label_password_weak1)
  25.             return (CODE_WEAK_PASSWORD, None)
  26.         elif password_strength == SAFE_2:
  27.             show_message(label_password_weak2)
  28.             return (CODE_WEAK_PASSWORD, None)
  29.     # 创建用户
  30.     return (CODE_SUCCESS, add_user(username, password))
复制代码


这样,在密码强度低于 SAFE_3 时,该函数就会返回一个状态码(CODE_WEAK_PASSWORD),并显示相应的消息。这可能解决了您的问题。

此外,我注意到代码中没有具体的 "Admin Tool",您提到的 "Admin Tool" 是另一个模块或者是界面部分吗?如果是,请确保在使用该工具添加或修改用户时,遵循同样的用户名和密码要求。

我希望这能解决您的问题。如果还有其他问题或细节需要了解,请随时告诉我!
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-7-17 14:57:35 | 显示全部楼层
根据你提供的代码,我看到在注册用户时会检查用户名是否已存在。如果使用"testuser"作为用户名,密码是"1111111111"时提示"用户已存在",这是因为在第80行检查用户名是否已被使用时,程序发现"testuser"已经存在于用户列表中,所以返回了状态码CODE_DUPLICATE,表示用户名已存在。你可以更改用户名或选择一个不存在的用户名进行测试。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-19 12:37:07 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-19 12:51:42 | 显示全部楼层
没明白你的意思
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-19 12:55:24 | 显示全部楼层

问题是为什么使用“testuser”做用户名,密码是“abcdABCDAB”的时候提示“用户已存在”?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-19 12:57:16 | 显示全部楼层
非常抱歉,但是我只能处理最多2048个字数token的请求。您提供的内容超过了我的处理能力,请缩短您的输入并重新提交问题,我将尽力回答。谢谢!
[Something went wrong, please try again later.]
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-19 12:59:33 | 显示全部楼层    本楼为最佳答案   
您的代码看上去非常整洁,但是在您的 "register" 函数中,您没有正确地返回密码强度检查的结果。当前的代码只有当密码强度达到 SAFE_3 或更高级别时,才会注册新用户,但是,如果密码强度低于 SAFE_3,函数并未返回任何状态码。这可能是您遇到“用户已存在”提示的原因。

您的 "register" 函数可以修改如下:

  1. def register(username, password):
  2.     """
  3.     注册一个用户
  4.     :param username: 用户名
  5.     :param password: 密码
  6.     :return: (状态码, 新用户)
  7.     """
  8.     # 检查用户名是否已被使用
  9.     users = [user.username for user in get_userlist()]
  10.     if username in users:
  11.         return (CODE_DUPLICATE, None)
  12.     if username == "Admin":
  13.         return (CODE_SUCCESS, add_user(username, password))
  14.     if not 3 <= len(username) < 11:
  15.         return (CODE_LENGTH_ERROR, None)
  16.     # 密码强度
  17.     password_strength = check_password_strength(password)
  18.     # 必须达到 SAFE_3 级别
  19.     if password_strength < SAFE_3:
  20.         if password_strength == SAFE_LOWEST:
  21.             show_message(label_password_weak0)
  22.             return (CODE_WEAK_PASSWORD, None)
  23.         elif password_strength == SAFE_1:
  24.             show_message(label_password_weak1)
  25.             return (CODE_WEAK_PASSWORD, None)
  26.         elif password_strength == SAFE_2:
  27.             show_message(label_password_weak2)
  28.             return (CODE_WEAK_PASSWORD, None)
  29.     # 创建用户
  30.     return (CODE_SUCCESS, add_user(username, password))
复制代码


这样,在密码强度低于 SAFE_3 时,该函数就会返回一个状态码(CODE_WEAK_PASSWORD),并显示相应的消息。这可能解决了您的问题。

此外,我注意到代码中没有具体的 "Admin Tool",您提到的 "Admin Tool" 是另一个模块或者是界面部分吗?如果是,请确保在使用该工具添加或修改用户时,遵循同样的用户名和密码要求。

我希望这能解决您的问题。如果还有其他问题或细节需要了解,请随时告诉我!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-7-19 13:09:43 | 显示全部楼层
isdkz 发表于 2023-7-19 12:59
您的代码看上去非常整洁,但是在您的 "register" 函数中,您没有正确地返回密码强度检查的结果。当前的代码 ...

谢,问题确实解决了,可是command register里我并没有检查返回值为none的情况啊
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-19 13:11:04 | 显示全部楼层
歌者文明清理员 发表于 2023-7-19 13:09
谢,问题确实解决了,可是command register里我并没有检查返回值为none的情况啊

Python中,当函数没有明确返回值的时候,默认返回的是None。如果你在使用command register并且没有考虑到返回None的情况,可能会在使用返回结果的时候遇到问题。

比如说,如果你试图对一个None值进行某种操作(如索引,迭代或者调用方法等)的话,Python会抛出一个TypeError。

这就是为什么在处理command register的返回值之前,我们通常会检查它是否为None。如果为None,那么我们可以根据具体情况来决定下一步的操作,比如抛出一个错误,返回一个默认值,或者跳过后续的操作。

以下是一个例子:

  1. result = command_register(args)
  2. if result is None:
  3.     print("Command not found!")
  4. else:
  5.     # 处理正常的结果
复制代码


在这个例子中,如果command_register返回None(也就是说,没有找到与给定参数匹配的命令),我们会打印一个错误信息,然后跳过后续的处理。如果找到了匹配的命令,我们就继续正常的处理。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-7-19 14:19:17 | 显示全部楼层
哇歌者你这代码写的漂亮啊

                               
登录/注册后可看大图

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-27 13:06

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表