Problems Faced with some login requirements. Please read the thread below

23 views
Skip to first unread message

vineeth sagar

unread,
Aug 1, 2018, 3:54:39 AM8/1/18
to Django users
Hi,

So we are currently doing a project where the client wants the session to expire at browser close and also prevent multiple logins from the same account. Well there are some ways to implement the multiple login thing, consider this say user closes the browser, the session cookie expires. When a new request comes in we cannot validate this to see if this is a new login request because of expiry or if this a second login from the same account. So there's no good way to implement this(I think).

I suggested this, have a rigid session expiry that is it expires in 'N' hours/minutes/seconds, So when a new request comes in we can validate with the session expiry in the db. If the session has not expired we know that he's trying to login for a second time. 
. I needed to change the session middleware to set the outgoing cookie only once. I only modified process_response, I pasted it below. I also added a new seessionstore class override two methods. The logic is simple, for the first time when a new request comes in, load is never invoked. So in create_db_instance we set an expiry date. When ever people try to modify the session, the load is invoked and we can get the expiry of the exisiting session from  that.

It's works fine without any side affects. From what I understand after reading through session modules for a 3 straight days, I am just posting it here so that I know if I have not done some thing stupid, I want to have a second set of eyes to validate my approach.



class NewSessionStore(SessionStore):
actual_expiry=None
def _get_session_from_db(self):
try:
return self.model.objects.get(
session_key=self.session_key,
expire_date__gt=timezone.now()
)
except (self.model.DoesNotExist, SuspiciousOperation) as e:
if isinstance(e, SuspiciousOperation):
logger = logging.getLogger(
'django.security.%s' % e.__class__.__name__)
logger.warning(str(e))
self._session_key = None
def load(self):
#print("In load")
s = self._get_session_from_db()
if s:
self.actual_expiry=s.expire_date
return self.decode(s.session_data) if s else {}
def create_model_instance(self, data):
"""
Return a new instance of the session model object, which represents the
current session state. Intended to be used for saving the session data
to the database.
"""
#print("In create_model_instance")
if not self.actual_expiry:
from datetime import datetime
print("Expire Time thats being set",datetime.now())
self.actual_expiry=self.get_expiry_date()
return self.model(
session_key=self._get_or_create_session_key(),
session_data=self.encode(data),
expire_date=self.actual_expiry,
)


def process_response(self, request, response):
"""
If request.session was modified, or if the configuration is to save the
session every time, save the changes and set a session cookie or delete
the session cookie if the session has been emptied.
"""
try:
accessed = request.session.accessed
modified = request.session.modified
empty = request.session.is_empty()
except AttributeError:
pass
else:
# First check if we need to delete this cookie.
# The session should be deleted only if the session is entirely empty
if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
response.delete_cookie(
settings.SESSION_COOKIE_NAME,
path=settings.SESSION_COOKIE_PATH,
domain=settings.SESSION_COOKIE_DOMAIN,
)
else:
if accessed:
patch_vary_headers(response, ('Cookie',))
if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty:
if request.session.get_expire_at_browser_close():
max_age = None
expires = None
else:
max_age = request.session.get_expiry_age()
if request.COOKIES.get(settings.SESSION_COOKIE_NAME):
pass
else:
expires_time = time.time()+max_age
expires = http_date(expires_time)
response.set_cookie(
settings.SESSION_COOKIE_NAME,
request.session.session_key, max_age=max_age,
expires=expires,
domain=settings.SESSION_COOKIE_DOMAIN,
path=settings.SESSION_COOKIE_PATH,
secure=settings.SESSION_COOKIE_SECURE or None,
httponly=settings.SESSION_COOKIE_HTTPONLY or None,
)
# Save the session data and refresh the client cookie.
# Skip session save for 500 responses, refs #3881.
if response.status_code != 500:
try:
request.session.save()
except UpdateError:
raise SuspiciousOperation(
"The request's session was deleted before the "
"request completed. The user may have logged "
"out in a concurrent request, for example."
)

Jason

unread,
Aug 1, 2018, 8:34:57 AM8/1/18
to Django users
About the only thing I would do is change your session storage db from your regular db to redis or memcached.  That would lower your db load with unnecessary session validation and offload it to either, which are built for fast key-value retrieval.

Not sure of your user load, but I would be hesitant to add anything to a project that can add an additional 150-400 requests/second load to the prod db cluster.
Reply all
Reply to author
Forward
0 new messages