Basi c автор защищенных просмотров в DRF - PullRequest
0 голосов
/ 09 апреля 2020

У меня есть некоторые конечные точки API, которые необходимо защитить с помощью HTTP Basi c Аутентификация в Django Rest Framework. В DRF есть BasicAuthentication , но на самом деле это аутентификация против пользователя в Django, а это не то, что я ищу.

Я нашел решение, используя пользовательское разрешение, но Это означает, что обезьяна исправляет представления, чтобы установить правильный заголовок проверки подлинности.

Есть ли лучший способ?

class BasicAuthPermission(permissions.BasePermission):
    def has_permission(self, request, view):
        credentials = view.credentials  # Will raise AttributeError on missing credentials
        realm = getattr(view, 'realm', 'Protected')
        auth = request.headers.get('Authorization')
        with suppress(ValueError, AttributeError):
            auth = b64decode(auth.split()[-1]).decode()
        if auth != credentials:
            # Monkey patch style
            view.get_authenticate_header = lambda r: f'Basic realm="{realm}"'
            raise exceptions.AuthenticationFailed('Bad credentials.')
        return True

Я считаю:

class ProtectedApiView(generics.GenericAPIView):
    permission_classes = [BasicAuthPermission]
    credentials = 'user:password'
    # ...

1 Ответ

0 голосов
/ 09 апреля 2020

Следуя предложению Араккала в комментарии, я сделал это с помощью класса Authentication. Это кажется менее хакерским, но я не могу установить учетные данные в представлении, как я делал изначально.

Я понимаю, что «анонимная аутентификация» - странное имя, но это потому, что Django ничего не знает о Пользователь. Так что для всех практических целей анонимно.

from base64 import b64decode
import binascii

from rest_framework import generics, exceptions, authentication

class AnonymousBasicAuthentication(authentication.BaseAuthentication):
    """
    HTTP Basic authentication against preset credentials.
    """
    www_authenticate_realm = 'api'
    credentials: str = None

    def authenticate(self, request):
        try:
            auth, encoded = authentication.get_authorization_header(request).split(maxsplit=1)
        except ValueError:
            raise exceptions.AuthenticationFailed('Invalid basic header.')

        if not auth or auth.lower() != b'basic':
            raise exceptions.AuthenticationFailed('Authentication needed')

        try:
            credentials = b64decode(encoded).decode(authentication.HTTP_HEADER_ENCODING)
        except (TypeError, UnicodeDecodeError, binascii.Error):
            raise exceptions.AuthenticationFailed('Invalid basic header. Credentials not correctly base64 encoded.')

        if self.credentials != credentials:
            raise exceptions.AuthenticationFailed('Invalid username/password.')

    def authenticate_header(self, request):
        return 'Basic realm="{}"'.format(self.www_authenticate_realm)


class MyAuthentication(AnonymousBasicAuthentication):
    credentials = 'user:password'


class MyProtectedView(generics.GenericAPIView):
    authentication_classes = [MyAuthentication]
    # ...
...