Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
828 views
in Technique[技术] by (71.8m points)

django - Is there a way to combine behavior of SESSION_EXPIRE_AT_BROWSER_CLOSE and SESSION_COOKIE_AGE

For security reasons I set SESSION_EXPIRE_AT_BROWSER_CLOSE to true.

But, browser-length cookies (cookies that expire as soon as the user closes his or her browser) don't have a expire time, then SESSION_COOKIE_AGE has no effects (Yes, I check it). But I want to set a logout/timeout on inactivity plus to logout on browse closing.

My question is, What is the best way to implement inactivity timeout/logout in browser-length cookies scenario?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As you explain, SESSION_EXPIRE_AT_BROWSER_CLOSE and SESSION_COOKIE_AGE are not compatible. When you set an expiration date to a cookie, the cookie becomes a no browser-length cookie.

In order to achieve your desired behaviour, you should set SESSION_EXPIRE_AT_BROWSER_CLOSE as True and control expire timeout by hand.

An elegant way to control by hand expire timeout is:

  1. Create a new custom middleware that control timeout.
  2. Modify settings.py to enable your custom middleware (and sessions).

The timeout custom middleware can looks like:

# updated version that should work with django 1.10 middleware style
# tested up to django 2.2

import time
from django.conf import settings
from django.contrib.auth import logout


class SessionIdleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.user.is_authenticated:
            if 'last_request' in request.session:
                elapsed = time.time() - request.session['last_request']
                if elapsed > settings.SESSION_IDLE_TIMEOUT:
                    del request.session['last_request'] 
                    logout(request)
                    # flushing the complete session is an option as well!
                    # request.session.flush()  
            request.session['last_request'] = time.time()
        else:
            if 'last_request' in request.session:
                del request.session['last_request']

        response = self.get_response(request)

        return response

Solution for ancient Django versions (pre 1.10)

class timeOutMiddleware(object):

    def process_request(self, request):
        if request.user.is_authenticated():
            if 'lastRequest' in request.session:            
                elapsedTime = datetime.datetime.now() - 
                              request.session['lastRequest']
                if elapsedTime.seconds > 15*60:
                    del request.session['lastRequest'] 
                    logout(request)

            request.session['lastRequest'] = datetime.datetime.now()
        else:
            if 'lastRequest' in request.session:
                del request.session['lastRequest'] 

        return None

Remember enable sessions in order to store lastRequest.

This solution is wrote and tested be me and is now working in my site. This code has GNU license ;)

New on django 1.6 ( ... two years later ... )

Datetime and timedelta values are only serializable if you are using the PickleSerializer. If not, perhaps easy solution is translate datetime to unix timestamp and back. Be free to post below this translation.

Edited

django-session-security app provides a mechanism to logout inactive authenticated users. Take a look.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...