【问题标题】:Basic auth protected views in DRFDRF 中的基本身份验证保护视图
【发布时间】:2020-07-21 16:10:58
【问题描述】:

我有一些 API 端点需要使用 Django Rest Framework 中的 HTTP 基本身份验证来保护。 DRF 中有 BasicAuthentication,但它实际上是针对 Django 中的用户进行身份验证的,这不是我想要的。

我找到了使用自定义权限的解决方案,但 ti 意味着猴子修补视图以设置正确的身份验证标头。

有没有更好的办法?

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

【问题讨论】:

  • 你的User和username:password之间没有任何关系?
  • 我认为这应该是一个认证程序而不是授权程序
  • Ruddra:没错。在实际代码中,我将凭据放在设置文件中,但为了清楚起见,我将字符串放在这里。
  • Arakkal:听起来很对。所以我想我写了一个自定义的身份验证类。
  • 此类不用于识别用户的身份验证应留在网络服务器(nginx、apache、...)上并保留在 Django 之外

标签: python django django-rest-framework


【解决方案1】:

按照 Arakkal 在评论中的建议,我改为使用 Authentication 类。它确实感觉不那么hacky,但我无法像最初那样在视图上设置凭据。

我意识到“匿名身份验证”是一个奇怪的名字,但那是因为 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]
    # ...

【讨论】:

    猜你喜欢
    • 2021-09-24
    • 2019-03-01
    • 1970-01-01
    • 2010-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多