views:

838

answers:

3

I want to only allow one authenticated session at a time for an individual login in my Django application. So if a user is logged into the webpage on a given IP address, and those same user credentials are used to login from a different IP address I want to do something (either logout the first user or deny access to the second user.)

+2  A: 

You'll need to do this with custom middleware.

In your middleware process_request() method you will have access to the request object so you can do something like the following:

session_key = request.session.session_key
ip_address = request.META.get('REMOTE_ADDR', '')

Now you know the IP address, so check a model you create that (roughly) would look like this:

class SessionIPS(models.Model):
    session = models.ForeignKey(Session)
    IP = models.CharField(max_length=20)

So when a session is created or deleted you will modifiy your session ip's table accordingly, and when a request comes in make sure the IP address isn't being used for another session. If if is, then return a Http404 (or something like it) from the middleware.

A pluggable app that can show you a lot more detail (and even includes IP address in its own model) is django-tracking.

Van Gale
+2  A: 

Django's middleware will probably help you achieve this. The issue is that you will probably want to allow multiple anonymous sessions from the same IP address, even authenticated sessions for different users, but not authenticated sessions for the same user.

You'll want to:

  1. Create a user profile model to store the IP address of a user's last login. See Django's Storing additional information about users documentation.

  2. Implement a custom authentication backend. This backend, when triggered and successfully authenticating a user (just call super) would wipe out the user's last login IP in the profile model.

  3. Implement a subclass of Django's django.contrib.sessions.SessionMiddleware class. Implement process_request. If the request.user object's profile model has no IP address, set it and allow the request. If it has an IP, and the IP is different from the current request's IP (request.META.REMOTE_ADDR), then do whatever you like to either log out the other user, or return an error to the requestor.

  4. Update your settings.py file so that your custom auth backend is processed first, and so that your custom session middleware is also processed first. This involves updating settings.AUTHENTICATION_BACKENDS and settings.MIDDLEWARE_CLASSES.

Jarret Hardie
+6  A: 

Not sure if this is still needed but thought I would share my solution:

1) Install django-tracking (thankyou for that tip Van Gale Google Maps + GeoIP is amazing!)

2) Add this middleware:

from django.contrib.sessions.models import Session
from tracking.models import Visitor
from datetime import datetime

class UserRestrictMiddleware(object):
"""
Prevents more than one user logging in at once from two different IPs
"""
def process_request(self, request):
    ip_address = request.META.get('REMOTE_ADDR','')
    try:
        last_login = request.user.last_login
    except:
        last_login = 0
    if unicode(last_login)==unicode(datetime.now())[:19]:
        previous_visitors = Visitor.objects.filter(user=request.user).exclude(ip_address=ip_address)
        for visitor in previous_visitors:
            Session.objects.filter(session_key=visitor.session_key).delete()
            visitor.user = None
            visitor.save()

3) Make sure it goes after the VisitorTrackingMiddleware and you should find previous logins are automatically bumped when someone new logs in :)

Nick Jones