import getpass
from passlib.hash import sha256_crypt
def register():
username = str(input('username '))
password = str(getpass.getpass('password ',stream=None))
exec('global '+username)
exec(username+'=user('+"'"+username+"'"+','+"'"+password+"'"+')')
def hashPassword(password):
Passhash = sha256_crypt.hash(password)
return Passhash
def verifyPassword(password,hashpass):
return sha256_crypt.verify(password,hashpass)
class user(object):
users=[]
def __init__(self, username, password):
password = str(password)
if len(password) <= 20:
self.username = username
user.users.append(username)
self.password = hashPassword(password)
else:
print("No more than 20 characters in the password")
def login(username, passsword):
if username in user.users:
if verifyPassword(password,exec(username+'.password'))==True:
print('logged in.')
else:
print('wrong password')
else:
print('unknown user.')
由于我对编码还很陌生,所以我试图建立一个基于文本的登录/注册系统。由于某种原因,使用register()
函数的某些操作无法正确注册用户,因为当我登录verifypassword()
时,它说
if verifyPassword(password,exec(username+'.password'))==True:
File "<string>", line 1, in <module>
NameError: name 'test' is not defined
>>>
如果有人可以告诉我发生了什么事。我认为它与全局变量有关,但我不知道如何解决
答案 0 :(得分:1)
global
中的exec
不起作用。使用globals()[var_name] = var_value
在全局范围内设置动态变量名称。
exec
通常是 {del} bad idea(如果使用用户提供的输入进行调用)。
它还在功能上(或多或少)具有意外行为,请参见以下示例:
def f():
exec('a=3')
print(a)
>>> f()
Traceback [...]
NameError: name 'a' is not defined
(这与在编译时已知局部作用域有关,请参见here或here)
此外,您可能会考虑将实际的user
对象存储在user.users
中-这样可以防止用户选择您在代码中实际使用的名称,并防止意外的行为
由于编译器知道您使用的是什么局部变量,因此可以通过字节码STORE_FAST
和LOAD_FAST
指令进行访问,这些指令在一种数组中进行存储和加载(您可以查看局部变量)通过f.__code__.co_varnames
命名),您不仅可以动态添加内容。
为什么这与global
有关?
好吧,如上所述,使用了STORE_FAST
和LOAD_FAST
指令(为了速度,您猜对了),以下功能的字节码将是:
>>> def f():
exec('global x')
x = 3
>>> dis.dis(f)
2 0 LOAD_GLOBAL 0 (exec)
2 LOAD_CONST 1 ('global x')
4 CALL_FUNCTION 1
6 POP_TOP
3 8 LOAD_CONST 2 (3)
10 STORE_FAST 0 (x)
12 LOAD_CONST 0 (None)
14 RETURN_VALUE
第一部分处理呼叫exec
。第二部分是作业。无论STORE_FAST
刚刚做什么,x
都会分配给 local 变量exec
。
这也是在exec
中创建新的局部变量无效的原因:它们没有空间。请注意,这对于exec
中设置的局部变量无效,但对于“通常”而言,它们仍然会分配空间。
答案 1 :(得分:0)
在python中,有一个全局变量字典,您可以通过调用globals()
来访问它。我不确定exec(...)
为何不起作用,但是我会考虑一种不同于将用户存储为变量(由用户名命名)的解决方案。但是要解决您的问题,请保留此设计选择,您可以像这样设置全局用户:globals()[username] = user(username, password)
,并在登录时执行verifyPassword(password, globals()[username].password)
。
但是由于全局变量实际上只是字典,因此最好自己维护用户字典。通过选择与另一个全局变量冲突的用户名,用户可能会覆盖全局变量。然后,您还可以消除users
类上的静态user
列表。可能看起来像这样,其中repository
是您与用户的字典:
import hashlib
import base64
import uuid
import getpass
from passlib.hash import sha256_crypt
repository = {}
def register():
username = str(input('username '))
password = str(getpass.getpass('password ',stream=None))
repository[username] = user(username, password)
def hashPassword(password):
Passhash = sha256_crypt.hash(password)
return Passhash
def verifyPassword(password,hashpass):
return sha256_crypt.verify(password,hashpass)
class user(object):
def __init__(self,username,password):
password = str(password)
if len(password) <= 20:
self.username = username
self.password = hashPassword(password)
else:
print("No more than 20 characters in the password")
def loginUser(username):
if username == 'exit':
start()
if username in repository:
if loginPass(username)==True:
print('success')
else:
print('passfail')
else:
print('incorrect login USERNAME NOT IN USER.USERS LIST')
def loginPass(username):
password = getpass.getpass('password ',stream=None)
if verifyPassword(password, repository[username].password) == True:
return True
else:
return False
def start():
while 1:
key1=input('login or register (l/r)')
if key1=='register':
del key1
register()
elif key1=='r':
del key1
register()
elif key1=='l':
del key1
loginUser(input('username or exit to got to l/r screen '))
else:
print('ERROR string not reconised among ifs')
start()