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...