Python 用户名和密码
我正在尝试创建一个程序,用户可以在其中创建账户、登录和删除账户。我已经准备了两个列表,一个是用户名列表,另一个是密码列表。这个脚本会询问你输入,如果你选择登录,它会显示:
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
我看到了一些问题:
- 你正在显示用户输入的密码。
- 你接受任何用户名和任何密码,这意味着我可以用我的密码登录任何账户。
- 绝对不要存储明文密码。
我还没有找到一种通用的方法来不显示密码。第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"
当然,在真正的系统中,你会把密码进行加盐和加密存储。