Django: Basic Auth for one view (avoid middleware) Django: Basic Auth for one view (avoid middleware) python python

Django: Basic Auth for one view (avoid middleware)


When you do a basic auth request, you're really adding credentials into the Authorization header. Before transit, these credentials are base64-encoded, so you need to decode them on receipt.

The following code snippet presumes that there's only one valid username and password:

import base64def my_view(request):    auth_header = request.META.get('HTTP_AUTHORIZATION', '')    token_type, _, credentials = auth_header.partition(' ')    expected = base64.b64encode(b'username:password').decode()    if token_type != 'Basic' or credentials != expected:        return HttpResponse(status=401)    # Your authenticated code here:    ...

If you wish to compare to the username and password of a User model, try the following instead:

def my_view(request):    auth_header = request.META.get('HTTP_AUTHORIZATION', '')    token_type, _, credentials = auth_header.partition(' ')    username, password = base64.b64decode(credentials).split(':')    try:        user = User.objects.get(username=username)    except User.DoesNotExist:        return HttpResponse(status=401)    password_valid = user.check_password(password)    if token_type != 'Basic' or not password_valid:        return HttpResponse(status=401)    # Your authenticated code here:    ...

Please note that this latter version is not extremely secure. At first glance, I can see that it is vulnerable to timing attacks, for example.


You can try a custom decorator (as seems to be the recommended way here and here) instead of adding new middleware:

my_app/decorators.py:

import base64from django.http import HttpResponsefrom django.contrib.auth import authenticatefrom django.conf import settingsdef basicauth(view):    def wrap(request, *args, **kwargs):        if 'HTTP_AUTHORIZATION' in request.META:            auth = request.META['HTTP_AUTHORIZATION'].split()            if len(auth) == 2:                if auth[0].lower() == "basic":                    uname, passwd = base64.b64decode(auth[1]).decode(                        "utf8"                    ).split(':', 1)                    user = authenticate(username=uname, password=passwd)                    if user is not None and user.is_active:                        request.user = user                        return view(request, *args, **kwargs)                response = HttpResponse()        response.status_code = 401        response['WWW-Authenticate'] = 'Basic realm="{}"'.format(            settings.BASIC_AUTH_REALM        )        return response    return wrap

Then use this to decorate your view:

from my_app.decorators import basicauth@basicauthdef my_view(request):    ...


This library could be used: https://github.com/hirokiky/django-basicauth

Basic auth utilities for Django.

The docs show how to use it:

Applying decorator to CBVs

To apply @basic_auth_requried decorator to Class Based Views, use django.utils.decorators.method_decorator.

Source: https://github.com/hirokiky/django-basicauth#applying-decorator-to-cbvs