Django - 用户关闭浏览器后会话持续多久
我正在尝试设置用户可以“尝试”密码的次数。目前,我想在会话中存储用户可以尝试密码的次数和“惩罚时间”。
我的问题是,用户关闭浏览器或更换IP地址会对会话产生影响吗?
举个例子,如果用户有5分钟的惩罚时间,这可以通过两个时间点相减来判断,如果大于5分钟,那么就让用户再试5次。如果用户在这段时间内关闭并重新打开浏览器,会话会丢失吗?
在用户登录之前的检查:
##############SESSION BASED##################
#Initialize tries, to be used later on
tries = "0"
try:
tries = request.session['tries']
except:
pass
#If tries > 5 times
if(int(tries) >= 5):
timeNow = request.session['locked_time']
timeDifferenceSeconds = (datetime.datetime.now() - datetime.datetime.strptime(timeNow, "%Y-%m-%d %H:%M:%S.%f")).total_seconds()
#See if the difference is greater than 15 minutes, otherwise lock
if(timeDifferenceSeconds > 900):
request.session['tries'] = str(0)
logger.info("User:" + str(username) + " is unlocked");
else:
logger.info("User:" + str(username) + " is currently locked");
logger.info("User:" + str(username) + " returning Locked");
return HttpResponse("Locked")
##############SESSION BASED##################
在用户输入错误登录信息后:
##############SESSION BASED##################
#if the user fails in providing the correct username/password, increment tries
try:
tries = request.session['tries']
num = int(tries)
num += 1
tries = str(num)
request.session['tries'] = str(tries)
except:
tries = 0
request.session['tries'] = str(tries)
#If tries > 5, then we will lock
if(int(tries) >= 5):
logger.info("User:" + str(username) + " is not valid, current tries:" + str(tries) + " and will be locked");
request.session['locked_time'] = str(datetime.datetime.now())
logger.info("User:" + str(username) + " returning Locked");
return HttpResponse("Locked")
else:
logger.info("User:" + str(username) + " is not valid, current tries:" + str(tries));
logger.info("User:" + str(username) + " returning Invalid");
return HttpResponse("Invalid")
##############SESSION BASED##################
目前我没有更改SESSION_COOKIE_AGE,所以默认是2周。
更新:
我使用了IP和用户标志的组合,虽然还没测试,但希望能有效。
在用户登录之前,检查:
- 他们的IP地址是否在“可疑列表”中,如果账户超过10个,就不能登录。
- 检查尝试次数,如果超过5次,就会锁定他们15分钟,锁定时间会根据他们违规的次数来计算(即超过5次尝试的次数)。
代码:
##############USER BASED AUTHENTICATION SYSTEM#####################
#Test for the user's public IP or best matched IP to see if it is banned
realIP = get_real_ip(request)
IP = get_ip(request)
#Get their realIP, and see if it matches, if they have over 10 accounts, then they are banned
try:
suspiciousIP = suspicousIP.objects.get(pk=realIP)
if(suspiciousIP.count > 10):
logger.info("User:" + str(username) + " has a banned real IP")
logger.info("User:" + str(username) + " returning Banned");
return HttpResponse("Banned")
except:
pass
#Get their IP, and see if it matches, if they have over 10 accounts, then they are banned
try:
suspiciousIP = suspicousIP.objects.get(pk=IP)
if(suspiciousIP.count > 10):
logger.info("User:" + str(username) + " has a banned IP")
logger.info("User:" + str(username) + " returning Banned");
return HttpResponse("Banned")
except:
pass
#Test the current user's blockedList
#2 conditions, if lockedTemp = True, then it is temporary locked until user has unlocked it
#by clicking the unlock email
#The other condition is whether tries > 5, and violations <= 5 (at 5th violation, the lockedTemp = true)
#then the user would need to wait until the time is over (900 seconds), which increases by each violation
userObject = None
try:
userObject = blockedList.objects.get(pk=username)
currentDateTime = datetime.datetime.now()
objectDateTime = datetime.datetime.strptime(str(userObject.dateTime), "%Y-%m-%d %H:%M:%S.%f")
lockedTemp = userObject.lockedTemp
tries = userObject.tries
violations = userObject.violations
if(lockedTemp == "True"):
logger.info("User:" + str(username) + " is temp locked");
logger.info("User:" + str(username) + " returning tempLock");
return HttpResponse("tempLock")
elif (tries >= 5 and violations <= 5 and lockedTemp != "True"):
timeDifferenceSeconds = (currentDateTime - objectDateTime).total_seconds()
if(timeDifferenceSeconds > 900 * violations):
userObject.tries = 0
userObject.save(update_field=['tries'])
logger.info("User:" + str(username) + " is unlocked, with tries:" + str(tries) + ", violations:" + str(violations))
else:
logger.info("User:" + str(username) + " is currently locked, with tries:" + str(tries) + ", violations:" + str(violations))
logger.info("User:" + str(username) + " returning Locked");
return HttpResponse("Locked")
except:
pass
##############USER BASED AUTHENTICATION SYSTEM#####################
在他们成功登录后:移除他们的阻止列表和可疑IP记录。
#See if the user's remember me is checked, if it is not checked, then
#the session cookie will automatically expire when the browser closes
if(rememberMe == "true"):
request.session.set_expiry(86400)
logger.info("User:" + str(username) + " has set their expiration to 1 day")
else:
request.session.set_expiry(0)
logger.info("User:" + str(username) + " has set their expiration to expire when browser closes")
#See if the user is marked in blockedList, if true, then delete their row
try:
userObject = blockedList.objects.get(pk=username)
userObject.delete()
logger.info("User:" + str(username) + " is in blockedList, removing their entry")
except:
logger.info("User:" + str(username) + " is NOT in blockedList")
pass
#See if the user's real IP is marked in suspicious IP, if true, then remove their entry
try:
suspiciousIP = suspicousIP.objects.get(pk=realIP)
suspiciousIP.delete()
logger.info("User:" + str(username) + " is in suspicious real IP, removing their entry")
except:
pass
#See if the user's IP is marked in suspicious IP, if true, then remove their entry
try:
suspiciousIP = suspicousIP.objects.get(pk=IP)
suspiciousIP.delete()
logger.info("User:" + str(username) + " is in suspicious IP, removing their entry")
except:
pass
如果他们输入错误的登录信息:
- 增加尝试次数,如果尝试次数超过5次,就会被锁定,锁定的“时间测试”会在登录之前进行。
- 如果他们有超过5次的违规记录,那么账户会被锁定,直到用户通过点击自动生成的邮件中的链接来解锁。
代码:
##############USER BASED AUTHENTICATION SYSTEM#####################
try:
#Get their current object, if exists, and increase their tries
userObject = blockedList.objects.get(pk=username)
userObject.tries += 1
#If their tries >= 5, then lock them temporary, and increase violation
if(userObject.tries >= 5):
logger.info("User:" + str(username) + " is not valid, current tries:" + str(userObject.tries) + " and will be locked");
userObject.violation += 1
userObject.dateTime = str(dateTime.dateTime.now())
#If violation >= 5, then we will tempLock, and can only be unlocked by email
if(userObject.violation >= 5):
logger.info("User:" + str(username) + " is not valid, will get TempLocked");
userObject.lockedTemp = "True"
userObject.save()
#Get their suspicious Real IPs, and increase them, or make a new one
try:
suspiciousIP = suspicousIP.objects.get(pk=realIP)
suspiciousIP.count += 1
suspiciousIP.save()
logger.info("User:" + str(username) + " has a suspeciousIP:" + str(suspiciousIP) + " current count:" + str(suspiciousIP.count));
except:
if realIP is not None:
newSuspiciousIP = suspicousIP(IP = realIP)
newSuspiciousIP.save()
logger.info("User:" + str(username) + " has a new suspeciousIP:" + str(realIP));
#Get their suspicious IPs, and increase them, or make a new one
try:
suspiciousIP = suspicousIP.objects.get(pk=IP)
suspiciousIP.count += 1
suspiciousIP.save()
logger.info("User:" + str(username) + " has a suspeciousIP:" + str(suspiciousIP) + " current count:" + str(suspiciousIP.count));
except:
if IP is not None:
newSuspiciousIP = suspicousIP(IP = IP)
newSuspiciousIP.save()
logger.info("User:" + str(username) + " has a new suspeciousIP:" + str(IP));
logger.info("User:" + str(username) + " returning tempLock");
logger.info("User:" + str(username) + " returning tempLock");
return HttpResponse("tempLock")
userObject.save()
logger.info("User:" + str(username) + " returning Locked");
return HttpResponse("Locked")
except:
newUsername = username
newRealIP = realIP
newIP = IP
newDateTime = ""
newTries = 1
newViolations = 0
newLockedTemp = "False"
newUserObject = blockedList(username=newUsername, realIP=newRealIP, IP = newIP,
dateTime = newDateTime, tries = newTries, violations = newViolations,
lockedTemp = newLockedTemp)
newUserObject.save()
logger.info("User:" + str(username) + " returning Invalid");
return HttpResponse("Invalid")
##############USER BASED AUTHENTICATION SYSTEM#####################
使用的额外模型:
class blockedList(models.Model):
username = models.CharField(max_length=200, primary_key=True)
realIP = models.CharField(max_length=200)
IP = models.CharField(max_length=200)
dateTime = models.CharField(max_length=200)
tries = models.IntegerField()
violations = models.IntegerField()
lockedTemp = models.CharField(max_length=200)
class suspicousIP(models.Model):
IP = models.CharField(max_length=200, primary_key=True)
count = models.IntegerField()
1 个回答
10
正如你在问题中提到的,Django中的会话(session)会根据SESSION_COOKIE_AGE
的设置来决定持续多长时间(默认是两周),这个时间是从上次“访问”开始计算的。
不过有两个例外:
- 你可以自己设置会话的过期时间,这样就会根据你设置的时间来决定。
- 如果手动把设置
SESSION_EXPIRE_AT_BROWSER_CLOSE
改为True
,那么每次用户关闭浏览器时,会话就会被清除。
但很重要的一点是,session的ID是存储在用户的浏览器的cookies里的,所以用户很容易就可以删除这些cookies,这样Django服务器就会把这当作一个新的会话。
另外一种实现你想要的功能的方法是把这些数据保存在用户的记录中——也就是说,如果用户user@example.com
尝试登录失败几次,你可以把这个用户名标记为禁止登录一段时间。你需要一个不同的数据库表来保存这些信息,并且要有自己的逻辑。我目前不知道有哪个应用是这样做的,但快速搜索一下可能会让我错得离谱。
这样,即使用户清除了他的会话,服务器也不会允许这个用户登录。