Python 用户名和密码

3 投票
9 回答
20075 浏览
提问于 2025-04-16 08:45

我正在尝试创建一个程序,用户可以在其中创建账户、登录和删除账户。我已经准备了两个列表,一个是用户名列表,另一个是密码列表。这个脚本会询问你输入,如果你选择登录,它会显示:

if loginchoice=='login':
    choice = raw_input("What is your username? ")
    choice2 = raw_input("What is your password? ")
    if choice in accounts:
        option1=1
    else:
        option1=0
    if choice2 in password:
        option2=1
    else:
        option2=0
    if option1==1 and option2==1:
        print "Welcome to Telemology,", choice
    else:
        print "The username or password you entered is incorrect. Please try again or register."

如你所见,它只是检查输入的内容是否已经在列表中。它并没有检查这些输入是否在列表中的位置是相同的。我不能使用 "accounts.index(choice)",因为它把 'choice' 当成了一个整数。对于字符串也是一样,它不会把它们当作变量来处理。有没有什么办法可以解决这个问题呢?

我希望如果我的问题得到解答,就不会出现两个用户同时注册导致索引出错的情况。

9 个回答

1

我看到了一些问题:

  1. 你正在显示用户输入的密码。
  2. 你接受任何用户名和任何密码,这意味着我可以用我的密码登录任何账户。
  3. 绝对不要存储明文密码。

我还没有找到一种通用的方法来不显示密码。第2个问题可以用字典来解决。至于第3个问题,你可能想使用hashlib模块:

from hashlib import sha224

PASSWORD_HASHES = {}

def set_password(account, raw_password):
    PASSWORD_HASHES[account] = sha224(raw_password).digest()

def authenticate(account, raw_password):
    if account not in PASSWORD_HASHES:
        return False
    return PASSWORD_HASHES[account] == sha224(raw_password).digest()

sha224替换成你想要的任何哈希算法;我没有跟踪哪些算法现在仍然适合用来处理密码。

编辑:关于第1个问题,如果你在一个基于POSIX的系统上(也就是说,不是在Windows命令提示符下),你可以使用Python的termios模块中的一些示例代码来获取密码,而不在屏幕上显示:

def getpass(prompt="Password: "):
    import termios, sys
    fd = sys.stdin.fileno()
    old = termios.tcgetattr(fd)
    new = termios.tcgetattr(fd)
    new[3] = new[3] & ~termios.ECHO          # lflags
    try:
        termios.tcsetattr(fd, termios.TCSADRAIN, new)
        passwd = raw_input(prompt)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old)
    return passwd

这个方法不会在输入字符时显示*,它只是抑制了输入。如果想要显示*,你需要逐个字符处理输入,并写更多的代码。

2

你应该使用getpass模块来确保密码不会显示在屏幕上,同时使用hashlib模块来保证原始密码不会被直接保存。下面是一个使用这两个模块的类,它可以在python2和python3上运行。如果你想把它从文件中加载出来,你可以把UserDB.users这个属性存储到一个文件里,可以使用json模块来实现这个功能。

import getpass
import hashlib
import random
import sys
class UserDB():
    def __init__(self, users=dict(), unprompt='Username:', pwprompt='Password:'):
        self.users=dict(users)
        self.unprompt=unprompt
        self.pwprompt=pwprompt
    def adduser(self):
        if sys.version_info.major==3:
            name=input(self.unprompt)
        elif sys.version_info.major==2:
            name=raw_input(self.unprompt)
        passwd=getpass.getpass(self.pwprompt).encode('utf-8')
        salt=bytes(random.randint(30, 95) for i in range(10))
        passwd=hashlib.pbkdf2_hmac('sha512', passwd, salt, 10*10)
        self.users[name]=[salt, passwd]
    def deluser(self, name):
        del self.users[name]
    def __str__(self):
        return str(self.users)
    def __repr__(self):
        return 'UserDB(users=%s, unprompt=%s, pwprompt=%s)' % (self.users,
                                                           ascii(self.unprompt),
                                                           ascii(self.pwprompt))
    def login(self):
        if sys.version_info.major==3:
            name=input(self.unprompt)
        elif sys.version_info.major==2:
            name=raw_input(self.unprompt)
        if name not in self.users:
            return False
        passwd=getpass.getpass(self.pwprompt).encode('utf-8')
        salt=self.users[name][0]
        passwd=hashlib.pbkdf2_hmac('sha512', passwd, salt, 10*10)
        return self.users[name][1]==passwd
2

你想要的是一种映射,或者说是字典。它的键是用户名,内容就是那个用户名对应的密码。

users = {} # this is the mapping
users["joe"] = "123" # it currently contains username "joe" with password "123"
...
username = raw_input("What is your username? ")
password = raw_input("What is your password? ")
if username in users.keys():
  expected_password = users[username]
  if expected_password == password:
    print "Welcome to Telemology,", username
  else:
    print "Didn't you forget your password,", username
else:
  print "Unknown user"

当然,在真正的系统中,你会把密码进行加盐和加密存储。

撰写回答