Проблема регистрации и входа в систему с помощью Tkinter

#python #authentication #tkinter #registration

Вопрос:

Я создаю систему входа и регистрации в tkinter. У меня есть несколько классов, поэтому я могу сделать его похожим на веб-сайт с несколькими страницами. Это выглядит так: введите описание изображения здесь

Итак, моя проблема в следующем: когда я регистрирую новую учетную запись, она записывает имя пользователя и пароль в файл txt. Теперь я пытаюсь заставить его выдавать ошибку, когда имя пользователя уже существует. Я попытался сделать это с помощью простого утверждения if. Это сработало в другом файле, но при работе с этими классами этого не происходит. Вот код для регистрации:

 def register_user():


    with open('user_data.txt', 'r ') as f:
        username_info = username.get()
        password_info = password.get()
        for line in f:
            if username_info not in line:
                f.write(username_info   ',')
                f.write(password_info   'n')
            else:
                Label(text='This user already exists!').pack()

    username_entry.delete(0, END)
    password_entry.delete(0, END)
 

Может ли кто-нибудь помочь мне с этим вопросом? Заранее спасибо!

Ниже я покажу весь свой код и свой текстовый файл:

 import tkinter as tk
from tkinter import *

class Page(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
    def show(self):
        self.lift()

class Page1(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       Label(self, text='').pack()
       Label(self, text='').pack()
       Label(self, text='').pack()
       Label(self, text="Hello welcome to Break-Through!").pack()



class Page2(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)

       username = StringVar()
       password = StringVar()

       Label(self, text='').pack()
       Label(self, text='').pack()
       Label(self, text='').pack()
       Label(self, text='Please enter details below').pack()
       Label(self, text='').pack()
       Label(self, text='Username * ').pack()
       Entry(self, textvariable=username).pack()
       Label(self, text='Password * ').pack()
       Entry(self, textvariable=password).pack()
       Label(self, text='').pack()
       Button(self, text='Login', width=10, height=1).pack()


def register_user():


    with open('user_data.txt', 'r ') as f:
        username_info = username.get()
        password_info = password.get()
        for line in f:
            if username_info not in line:
                f.write(username_info   ',')
                f.write(password_info   'n')
            else:
                Label(text='This user already exists!').pack()

    username_entry.delete(0, END)
    password_entry.delete(0, END)


class Page3(Page):
    def __init__(self, *args, **kwargs):
        Page.__init__(self, *args, **kwargs)

        global username
        global password
        global username_entry
        global password_entry

        username = StringVar()
        password = StringVar()

        Label(self, text='').pack()
        Label(self, text='').pack()
        Label(self, text='').pack()
        Label(self, text='Please enter details below').pack()
        Label(self, text='').pack()
        Label(self, text='Username * ').pack()
        username_entry = Entry(self, textvariable=username)
        username_entry.pack()
        Label(self, text='Password * ').pack()
        password_entry = Entry(self, textvariable=password)
        password_entry.pack()
        Label(self, text='').pack()
        Button(self, text='Register', width=10, height=1, command=register_user).pack()




class MainView(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        p1 = Page1(self)
        p2 = Page2(self)
        p3 = Page3(self)

        buttonframe = tk.Frame(self)
        container = tk.Frame(self)
        buttonframe.pack(side="top", fill="x", expand=False)
        container.pack(side="top", fill="both", expand=True)

        p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p2.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p3.place(in_=container, x=0, y=0, relwidth=1, relheight=1)


        main_screen = tk.Button(buttonframe, text="Main-Screen", width=30, height=2, command=p1.show)
        login = tk.Button(buttonframe, text="Login", width=30, height=2, command=p2.show)
        register = tk.Button(buttonframe, text="Register", width=30, height=2, command=p3.show)

        main_screen.pack(side='left')
        login.pack(side='left')
        register.pack(side='left')



        p1.show()

if __name__ == "__main__":
    root = tk.Tk()
    main = MainView(root)
    main.pack(side="top", fill="both", expand=True)
    root.wm_geometry("800x800")
    root.mainloop()

 

вот как выглядит текстовый файл с пользовательскими данными. Но он продолжает добавлять пользователей, которые уже существуют

 a,a
b,b
c,c
d,d

 

Комментарии:

1. Не стоит слишком беспокоиться об этом прямо сейчас, но вам, вероятно, не следует сохранять пароли в виде открытого текста, хэшировать их или шифровать.

Ответ №1:

Проблема вызвана тем, как вы открываете и читаете файл. При использовании with open('user_data.txt', 'r ') as f: вам предоставляется файловый объект, f . Это не текстовое содержимое файла, это объект, представляющий его. Объект file также является итератором, поэтому for line in f он будет работать, так как вы можете перебирать строки в файле, но это неправильный способ чтения файла. Проблема в том, что при использовании f.write итератора перестает работать, поэтому программа проверяет только первую строку файла. Вместо for line in f этого используйте for line in f.read().splitlines() . .read() получает текстовое содержимое из объекта file. Это все одна строка с символами новой строки. Чтобы превратить его в список строк, мы можем использовать .splitlines() . Это превращает блок текста в список строк. Поскольку мы больше не полагаемся на f итератор, цикл for будет просматривать каждую строку в файле.

Это вызывает вторую проблему — для каждой строки в файле вы проверяете, использовалось ли имя ранее, поэтому для каждой строки, где его нет, вы вставляете другую. Это означает, что в конечном итоге вы вставляете запись более одного раза, чего вам не нужно. Чтобы исправить это, вам нужно сначала проверить, является ли имя пользователя уникальным, а затем записать новую запись. Вот фиксированная register_user функция:

 def register_user():
    with open('user_data.txt', 'r ') as f:
        username_info = username.get()
        password_info = password.get()
        username_good = True
        for line in f.read().splitlines():
            if username_info == line.split(",")[0]:
                username_good = False
                break #Stop the for loop from continuing
        if username_good:
            f.write(username_info   ","   password_info   "n")
        else:
            Label(text='This user already exists!').pack()
    username_entry.delete(0, END)
    password_entry.delete(0, END)
 

Я использовал username_good , чтобы отслеживать, является ли имя пользователя уникальным или нет. Затем он проходит по строкам в файле. Для каждой строки он проверяет username_info , равен ли line.split(",")[0] . Это отличается от того, как вы делали это раньше, так как он разбивает строку на имя пользователя и пароль и проверяет только имя пользователя. В противном случае у пользователя не могло быть имени пользователя, которое было бы частью другого имени пользователя или пароля (например , если пользователь хотел получить имя пользователя alex , но у кого-то оно уже было alexander , ему бы это не разрешили, потому alex что оно есть, alexander даже если у них разные имена пользователей). Если он находит неуникальное имя пользователя, он устанавливает username_good ложному и разрывает цикл, чтобы он больше не проверял строки. После завершения цикла for вы можете проверить username_good . Если это правда, то дубликатов не найдено, поэтому вы можете записать новую строку в файл. В противном случае вы можете создать метку. Запись файла теперь должна работать по назначению.

Комментарии:

1. О, большое вам спасибо за ваш идеальный ответ!!

Ответ №2:

Если вы хорошенько подумаете о цикле for:

 for line in f:
    if username_info not in line:
        # when username_info is not found in current line
        # the file pointer will be moved to EOF due to f.write()
        f.write(username_info   ',')
        f.write(password_info   'n')
        # as the file pointer is at EOF, the for loop will be terminated
    else:
        Label(text='This user already exists!').pack()
 

Всякий username_info раз, когда в строке не найдено, учетные данные будут добавлены в конец файла и разорвут цикл for.

Ниже приведен один из способов использования цикла for для ваших целей:

 for line in f:
    user, passwd = line.strip().split(',')
    if username_info == user:
        # better create the label once and update its text here instead
        Label(text=f'User "{username_info}" already exists!').pack()
        break
else:
    # user not found, so register user
    f.write(f'{username_info},{password_info}n')