Rolling your own authentication in Django

For various reasons I wanted to see just what was required to roll my own basic authentication using Django. I am aware there’s a built-in authentication module, django.contrib.auth, but it’s overkill for my ultimate goal and it depends on the session module in ways that only further study can reveal. I heard rumours that the authentication module would be pluggable. The only pluggable aspect of it that I found was the backend (i.e. the data model).

In the end the most relevant reason for doing this was that I wanted to :-)

So, what’s involved in it? It turns out, not much!

First I created a middleware class that extracts the authentication credentials (read username and password) and sticks a ‘user object’ in the request depending on just how successfully it does this:

from base64 import b64decode
from models import User, AnonUser, BadUser

class MiniAuthMiddleWare(object):
    def process_request(self, request):
        auth = request.META.get('Authorization', '') or \
                request.META.get('HTTP_AUTHORIZATION', '')
        if not auth:
            request.user = AnonUser()
            return

        name, pwd = b64decode(auth[6:]).split(':')
        try:
            u = User.objects.get(name=name)
            if pwd != u.passwd:
                request.user = BadUser()
                return
            request.user = u
            return
        except User.DoesNotExist, e:
            request.user = BadUser()
        except AssertionError, e:
            request.user = BadUser()

        return

The model related to this is rather minimal:

from django.db import models

class User(models.Model):
    name = models.CharField(maxlength=50, primary_key=True)
    passwd = models.CharField(maxlength=50)

    def is_authenticated(self):
        return True

class AnonUser:
    name = 'Anonymous'
    passwd = 'NoPass'

    def is_authenticated(self):
        return False

class BadUser:
    name = 'BadUser'
    passwd = 'NoPass'

    def is_authenticated(self):
        return False

Then I decorated the functions/urls that required authentication with the following:

def _RequireAuthorization(func):
    def _wrapper(request):
        if not request.user.is_authenticated():
            response = HttpResponse()
            response.status_code = 401
            response['WWW-Authenticate'] = 'Basic Realm="Silly Realm"'
            return response
        else:
            return func(request)
    return _wrapper

That all seems to work just fine :-)

Share

3 Comments

  1. Pingback: therning.org/ magnus » Django is cute

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>