Django: Basic Auth for one view (avoid middleware)

前端 未结 4 1149
星月不相逢
星月不相逢 2021-02-18 23:46

I need to provide http-basic-auth to one view.

I want to avoid modifying the middleware settings.

Background: This is a view which gets fil

相关标签:
4条回答
  • 2021-02-19 00:00

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

    0 讨论(0)
  • 2021-02-19 00:09

    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 base64
    
    from django.http import HttpResponse
    from django.contrib.auth import authenticate
    from django.conf import settings
    
    
    def 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
    
    
    @basicauth
    def my_view(request):
        ...
    
    0 讨论(0)
  • 2021-02-19 00:10

    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

    0 讨论(0)
  • 2021-02-19 00:14

    For those that already use django-rest-framework (DRF):

    DRF has a BasicAuthentication class which, more-or-less, does what is described in the other answers (see source).

    This class can also be used in "normal" Django views.

    For example:

    from rest_framework.authentication import BasicAuthentication
    
    def my_view(request):
        # use django-rest-framework's basic authentication to get user
        user = None
        user_auth_tuple = BasicAuthentication().authenticate(request)
        if user_auth_tuple is not None:
            user, _ = user_auth_tuple
    
    0 讨论(0)
提交回复
热议问题