如何在python-django中三次输入错误密码时锁定用户



我试图写一个登录页面,通过三次输入错误的密码来锁定用户,用户名将进入黑名单,从而被锁定。登录页面运行良好,黑名单运行良好。一个问题是循环不起作用,我一开始有while count < 3,但它只给用户一次输入密码的机会,然后我将代码重写为if ... elif...格式,以检查出了什么问题。我发现它卡在";1用户名或密码不正确1";这意味着它只进入第一个if,并且计数总是1,这意味着计数每次都返回0。

我认为这是因为用户点击登录按钮后,页面刷新并使计数再次为0,那么我应该如何解决呢?

@unauthenticated_user
def loginPage(request):
if request.method == "POST":
username = request.POST.get('username')  # Get username input first
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
BL = BlackList.objects.values_list('list', flat=True)  # Read all data into array
if username in BL:  # Check if the username is in blacklist
messages.info(request, 'Username in black list, please contact admin')
else:  # Not in black list username can go to login
count = 0
if count == 0:  # User can try 3 times for each login in
if user is not None:
login(request, user)
return redirect('home')
else:
count += 1
messages.info(request, '1 Username or Password is incorrect' + str(count))
elif count == 1:
messages.info(request, 'testest' + str(count))
request.method == "POST"
username = request.POST.get('username')  # Get username input first
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
count += 1
messages.info(request, '2 Username or Password is incorrect' + str(count))
elif count == 2:
request.method == "POST"
username = request.POST.get('username')  # Get username input first
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
count += 1
messages.info(request, '3 Username or Password is incorrect' + str(count))
else:  # 3 times fail the username will go to the black list
BlackList.objects.create(list=username)
# Put the username in to BlackList
messages.info(request, 'Username in black list, please contact admin')
context = {}
return render(request, 'accounts/login.html', context)

您可以在会话中存储计数。

if request.session.get('count', 0) == 0:
request.session['count'] = 1
else:
request.session['count'] += 1
if request.session['count'] == 3:
pass       # ban him

如果你的黑名单没有保存在服务器的数据库或文本文件中,用户将能够通过刷新网页绕过你的防线。因此,您必须将黑名单存储在运行时之外。

最有效的方法是创建一个简单的文本文件来保存列入黑名单的用户名,该文件将存储在服务器中。这也会阻止该用户名使用其他设备登录。

请尝试用此代码替换您的代码。

if request.method == "POST":
username = request.POST.get('username')  # Get username input first
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)

with open("blacklist.txt", "a") as BlackL:
pass

with open("blacklist.txt") as BlackL:
for BL in Black:
if username == BL: #This one checks if username in blacklist
return "User name in blacklist, contact admin."

else:  # Not in black list username can go to login
count = 0
if count == 0:  # User can try 3 times for each login in
if user is not None:
login(request, user)
return redirect('home')
else:
count += 1
messages.info(request, '1 Username or Password is incorrect' + str(count))
elif count == 1:
messages.info(request, 'testest' + str(count))
request.method == "POST"
username = request.POST.get('username')  # Get username input first
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
count += 1
messages.info(request, '2 Username or Password is incorrect' + str(count))
else count == 2:
request.method == "POST"
username = request.POST.get('username')  # Get username input first
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
count += 1
with open("blacklist.txt", "a") as BlackL:
print(username, file=BlackL)
return "User name in blacklist, contact admin."

context = {}
return render(request, 'accounts/login.html', context)

我无法在我的计算机中运行代码,但我相信如果有任何错误,你可以自己调试

由于这在谷歌上出现得很高,而且我看不到合适的解决方案,我将在这里提供我的解决方案:

这些信息最适合居住的地方很可能是数据库中的用户模型。

在我的用户模型中:

class SystemUser(AbstractUser):
logins_failed("Number of failed login attempts", default=0)
...

然后,每次提供正确的用户名和错误的密码时,您都可以添加到此计数器。并阻止尝试次数过多的用户登录。

视图.py

def login(request):
if request.method == "POST":
form = LoginForm(request.POST)

if form.is_valid()
unauthenticated_user = None
user = None

try:
unauthenticated_user = SystemUser.objects.get(email=form.cleaned_data["username"].lower())
user = authenticate(request, username=unauthenticated_user.username, password=form.cleaned_date["password"])
except SystemUser.DoesNotExist:
# We pass this error, as we will handle it below with added logic for failed logins-count
pass
if not user:
form.add_error(field="username", error="Wrong password or unknown username. Please try again.")

# If user does not exist, but we have an unauthenticated_user
# It means the provided password was wrong
if unauthenticated_user:
unauthenticated_user.logins_failed += 1
unauthenticated_user.save()
elif user.logins_failed >= 3:
# If the user exists but have too many attempts we inform the user that they're locked out
form.add_error(field=None, error="You're locked out of the system due to too many attempts. Contact your admin.")
else:
# Username and password is correct, we allow the user to login
login(request, user)

# Remember to reset the failed logins-count
user.logins_failed = 0
user.save()
return redirect(reverse("homepage"))
else:
# If it wasn't a POST-request we send the user to the empty login-page
form = SystemUserLoginForm()

return render(request, "userlogin.html", {"form": form})

正如您可能已经注意到的,只要用户提供了错误的密码,该解决方案就会继续计算超过三次的错误密码尝试。只有当用户提供了正确的密码时,才会通知他们已被锁定。这样做的好处是不会让我们的用户暴露在使用不同电子邮件地址进行测试的潜在入侵者面前。

请记住添加管理员重置此计数器的功能,以允许用户再次登录。

还要考虑你对潜在的";重置密码"-功能。是否应允许被阻止的用户重置密码?如果是这样,您还必须在此过程中重置计数器。

最新更新