72

I'm using this to login the user in:

def login_backend(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user is not None:
            login(request, user)
            request.session.set_expiry(300)
            return HttpResponseRedirect('/overview/')
        else:
            return HttpResponseRedirect('/login_backend/')
    else:
        return render_to_response('login_backend.html', context_instance=RequestContext(request))

I want session to expire after 5mins thus I added request.session.set_expiry(300) in the view above. But the session is never expiring. What am I doing wrong?

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
pynovice
  • 7,424
  • 25
  • 69
  • 109
  • 1
    I've already answer this same question, here is the link http://stackoverflow.com/questions/14808238/middleware-is-not-work-expected/14808426#14808426. If you have clarification, just tell me – catherine Feb 12 '13 at 10:53
  • If the user is opening the application, I don't want session to expire. If the user didn't open the application for 5minutes I want session to expire. – pynovice Feb 12 '13 at 11:02
  • Yeah that's right, that's what my answer is. If the user is idle then it will auto logout. Do you want me to post the whole answer here? – catherine Feb 12 '13 at 11:06
  • Yeah, do that. I will mark your answer correct then. – pynovice Feb 12 '13 at 11:08

11 Answers11

78

There are two parameters to expire sessions, SESSION_EXPIRE_AT_BROWSER_CLOSE and SESSION_COOKIE_AGE. If you want to expire in 5 minutes yours settings should like as:

SESSION_EXPIRE_AT_BROWSER_CLOSE = False
SESSION_COOKIE_AGE = 5 * 60

To combine both learn how do it writing your custom middleware "Is there a way to combine behavior of SESSION_EXPIRE_AT_BROWSER_CLOSE and SESSION_COOKIE_AGE"

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
dani herrera
  • 48,760
  • 8
  • 117
  • 177
  • If the user is opening the application, I don't want session to expire. If the user didn't open the application for 5minutes I want session to expire. – pynovice Feb 12 '13 at 11:02
  • Notice that my middleware code check for request.user.is_authenticated(). – dani herrera Feb 12 '13 at 11:07
41

Update for Django 1.6

The middleware code below is not working in Django 1.6 and above version because of json serializable. To make it work in all versions of Django, put the session serializer.

settings.py

#Handle session is not Json Serializable
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'

The above sample of serializer is for Django 1.6. Kindly search for other version. Thanks...

Create middleware.py

from datetime import datetime, timedelta
from django.conf import settings
from django.contrib import auth


class AutoLogout:
  def process_request(self, request):
    if not request.user.is_authenticated() :
      #Can't log out if not logged in
      return

    try:
      if datetime.now() - request.session['last_touch'] > timedelta( 0, settings.AUTO_LOGOUT_DELAY * 60, 0):
        auth.logout(request)
        del request.session['last_touch']
        return
    except KeyError:
      pass

    request.session['last_touch'] = datetime.now()

Update your settings.py:

MIDDLEWARE_CLASSES = [
    .........................

    'app_name.middleware.AutoLogout', 
]

# Auto logout delay in minutes
AUTO_LOGOUT_DELAY = 5 #equivalent to 5 minutes
catherine
  • 22,492
  • 12
  • 61
  • 85
  • @hec it will work if you put the setting for session serializer that would fix the ` is not json serializable` – catherine Mar 19 '14 at 10:00
  • Or you could change datetime.now() to time.time(). Make other small relevant changes to condition logic, and it works on the JSON serializer. – Hec Mar 19 '14 at 16:44
  • @Hec that's fine also. The session serializer is for overall not only in datetime. Thanks... :) – catherine Mar 20 '14 at 07:26
  • 1
    @catherine, why your code is different than code I linked in [my answer](http://stackoverflow.com/a/14830874/842935) that is wrote 1 year ago before yours? – dani herrera May 29 '14 at 08:26
  • **PickleSerializer** rocks! (Django 1.8 - same path to it) – madzohan Jun 17 '15 at 12:27
  • @catherine I would like to develop my own middleware to logout user after inactivity ; I try to understand your code and implent it with new django way of writting middleware but do not understand one thing : **when request.session['last_touch'] is set for the first time?** – SLATER Nov 29 '19 at 08:25
26

Django 1.9

Edit your settings.py and add the following:

# SESSION AGE 5 Minutes
SESSION_COOKIE_AGE = 5*60
Slipstream
  • 13,455
  • 3
  • 59
  • 45
18

Depending on your project, this might not be sufficient.

For example, what if the user spends 6 minutes filling a form and clicks "Save" ? Browser will be redirected to the login page and form data will be lost.

Also, there is a potential security issue if the user leaves his workstation with confidential data in an opened page of the browser.

Also, what if the user reads a page during 6 minutes ? It is then not really cool to log him out without warning or any way to extend his session ...

Considering these matters, you might find django-session-security useful.

jpic
  • 32,891
  • 5
  • 112
  • 113
  • 3
    Tried out django-session-security. Installs like a breeze, works like a charm. Thank you for making such a wonderful module! – Saurabh Hirani May 13 '14 at 14:06
  • 1
    This package worked well for me using Django 2.2. There were a few necessary tweaks to the instructions provided in the documentation, as it was written for Django pre-1.10: - `session_security.middleware.SessionSecurityMiddleware` is added to the `MIDDLEWARE` list instead of `MIDDLEWARE_CLASSES` which doesn't exist anymore - It's `"django.template.context_processors.request"` instead of `"django.core.context_processors.request"` that must be added to the list of `"context_processors"` under `"OPTIONS"` in `TEMPLATES` – Nano Tellez Dec 09 '20 at 23:14
9

I use Django 2.1.7 and the easiest way to expire django session is:

  • first you need to install django-session-timeout with command:

    pip install django-session-timeout

  • then you need to update your SessionTimeoutMiddleware in settings.py

    MIDDLEWARE_CLASSES = [
         ...
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django_session_timeout.middleware.SessionTimeoutMiddleware',
         ...
    ]
    
  • at last you need to add SESSION_EXPIRE_SECONDS at the end of settings.py:

    SESSION_EXPIRE_SECONDS = 300 # 300 seconds = 5 minutes

By default, the session will expire X seconds after the start of the session. To expire the session X seconds after the last activity, use the following setting:

SESSION_EXPIRE_AFTER_LAST_ACTIVITY = True

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Mihael Waschl
  • 330
  • 1
  • 6
  • 19
  • 1
    Unfortunately awsebcli needs the package 'six' in version 1.11 (but not higher) while django-session-timeout forces 1.12. So therefore not an option for me :( – Greg Holst Aug 16 '19 at 10:38
  • 1
    This solution also works in my Django 4.0 project. Thanks! – NullIsNot0 Jan 19 '22 at 17:08
7

Set session time needed before calling login()!

...
request.session.set_expiry(300)
login(request, user)
...     
4

This works for me

settings.py

TIME= 240*60  //four hours  or your time
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
SESSION_EXPIRE_AT_BROWSER_CLOSE= True
SESSION_COOKIE_AGE = TIME    //change expired session
SESSION_IDLE_TIMEOUT = TIME  //logout

middleware.py

from django.contrib.auth import logout
from django.contrib import messages
import datetime
from django.shortcuts import redirect

import settings

class SessionIdleTimeout:
    def process_request(self, request):
        if request.user.is_authenticated():
            current_datetime = datetime.datetime.now()
            if ('last_login' in request.session):
                last = (current_datetime - request.session['last_login']).seconds
                if last > settings.SESSION_IDLE_TIMEOUT:
                    logout(request, login.html)
            else:
                request.session['last_login'] = current_datetime
        return None
jhonny lopez
  • 325
  • 1
  • 2
  • 9
4

To bring @jhonnylopez's answer up to date and to log out after a period of inactivity, rather than after a given time:

settings.py

# Logout after a period of inactivity
INACTIVE_TIME = 15*60  # 15 minutes - or whatever period you think appropriate
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
SESSION_EXPIRE_AT_BROWSER_CLOSE= True
SESSION_COOKIE_AGE = INACTIVE_TIME   # change expired session
SESSION_IDLE_TIMEOUT = INACTIVE_TIME  # logout

middleware.py

from django.contrib.auth import logout
import datetime

from settings import SESSION_IDLE_TIMEOUT


class SessionIdleTimeout(object):
    """Middle ware to ensure user gets logged out after defined period if inactvity."""
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.user.is_authenticated:
            current_datetime = datetime.datetime.now()
            if 'last_active_time' in request.session:
                idle_period = (current_datetime - request.session['last_active_time']).seconds
                if idle_period > SESSION_IDLE_TIMEOUT:
                    logout(request, 'login.html')
            request.session['last_active_time'] = current_datetime

        response = self.get_response(request)
        return response
Psionman
  • 3,084
  • 1
  • 32
  • 65
3

To "settings.py", set SESSION_COOKIE_AGE which is 1209600 seconds(2 weeks) by default and SESSION_SAVE_EVERY_REQUEST which is "False" by default as shown below:

# "settings.py"

SESSION_COOKIE_AGE = 180 # 3 minutes. "1209600(2 weeks)" by default

SESSION_SAVE_EVERY_REQUEST = True # "False" by default

If SESSION_SAVE_EVERY_REQUEST is "True", users are logged out after SESSION_COOKIE_AGE and each time users access Django Website, session expiry time is updated so users don't need to log in frequently.

If SESSION_SAVE_EVERY_REQUEST is "False", users are logged out after SESSION_COOKIE_AGE but each time users access Django Website, session expiry time is not updated so users need to log in frequently.

Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
2

If you are looking for simple expiry after 5 minutes and do not care about prompting the user or allowing them to extend the session, django-session-timeout works well.

pip install django-session-timeout
SESSION_EXPIRE_SECONDS = 300  # 5 min
SESSION_EXPIRE_AFTER_LAST_ACTIVITY = True
SESSION_TIMEOUT_REDIRECT = '/accounts/logout/'  # redirect to whatever page

While this is a quick fix for session expiry after 5 min, with redirect to a specified page (logout), it does not help with some of the other issues addressed in this post around warning the user or giving the opportunity to extend a session. With the last activity setting set to True, it will continue to extend the session based on activity, however if they are reading a page or filling out a form that takes longer than 5 minutes, it will log them out, possibly causing issues for your users depending on your site functionality.

Further documentation here: https://pypi.org/project/django-session-timeout/

I have not implemented it yet, but plan to next. Some other posts have recommended django-session-security if you need added functionality of prompting the user and allowing them the option to extend the session.

These are good alternatives to not adding your own middleware, if that is not the route you want to go.

JSS
  • 174
  • 9
1

Session needs to be set before calling login() as pointed out by Dmitry Nikitin. Also you need to add SESSION_SAVE_EVERY_REQUEST = True in the settings file. This settings will keep updating the expiry time with every request. So after 5 minutes of inactivity, session will expire.