Virittelin Djangon käyttämään tavallista HTTP-autentikointia kustomoidusta käyttäjätaulusta, mikä osoittautui hieman haastavaksi. Django käyttää normaalisti cookie-pohjaista autentikointia ja omaa määrämuotoista auth_user-taulua. Sen takia päätin ohittaa sisäänrakennetun autentikoinnin kokonaan ja tehdä oman.
Ensimmäinen vaatimus on saada Apache välittämään Authorization-headeri Djangolle sellaisenaan. Itse käytän Apachen mod_fastcgi:tä kehityksessä, ja tämä edellytti seuraavanlaista direktiiviä Apachen konfiguraatiossa (oleellista on -pass-header Authorization):
FastCGIExternalServer /var/www/html/django.fcgi -socket /tmp/django.sock -pass-header Authorization
Tämän jälkeen Django-sovelluksen views.py-moduuliin voi lisätä muutaman tarpeellisen funktion (User-luokka on itse määrittelemäni malli käyttäjätaululle):
def parse_http_auth(request): "Parse HTTP Basic Authorization and return (username, password) or ('', '')." for header in ['HTTP_AUTHORIZATION', 'Authorization']: if header in request.META: auth = request.META[header].split() if (len(auth) == 2) and (auth[0].lower() == "basic"): uname, passwd = base64.b64decode(auth[1]).split(':') return uname, passwd return ('', '')def authenticate_user(request): "Authenticate user with HTTP Basic Authentication. Return User object or None." (uname, passwd) = parse_http_auth(request) if (len(uname) > 0) and (len(passwd) > 0): user = User.objects.get(login=uname) if passwd == user.password: return user return None
Viimeinen tarvittava apuväline on @require_auth-dekoraattori, jonka avulla on helppo määritellä ne näkymät, joilta vaaditaan autentikointia. Dekoraattori lisää autentikoidun käyttäjän keyword-argumenttina näkymäfunktiolle, jolloin def index(request) tuleekin muotoon def index(request, user):
class require_auth: "Custom authentication decorator, will inject User object as kw arg 'user' to caller or return error." def __init__(self, func): self.func = func def __call__(__self, *__args, **__kw): request = __args[0] user = authenticate_user(request) if user == None: response = HttpResponse('<html><body><h1>401 Unauthorized</h1><p>Authorization is required.</p></body></html>') response.status_code = 401 response['WWW-Authenticate'] = 'Basic realm="Django"' return response __kw['user'] = user return __self.func(*__args, **__kw)
Näiden jälkeen voi sitten alkaa lisäillä dekoraattoria tavallisiin näkymäfunktioihin:
@require_auth def index(request, user): return render_to_response('index.html')
Näyttäisi toimivan. En tiedä onko tämä ratkaisu yksinkertaisin mahdollinen...