【问题标题】:Django: Basic Auth for one view (avoid middleware)Django:一个视图的基本身份验证(避免中间件)
【发布时间】:2018-03-07 16:34:51
【问题描述】:

我需要为一个视图提供http-basic-auth。

我想避免修改中间件设置。

背景:这是一个由远程应用程序填充的视图。

【问题讨论】:

    标签: python django authentication basic-authentication http-authentication


    【解决方案1】:

    您可以尝试自定义装饰器(似乎是推荐的方式 here 和 here),而不是添加新的中间件:

    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
    

    然后用它来装饰你的视图:

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

    【讨论】:

    • 上面的代码示例中似乎有错误。它应该是uname, passwd = base64.b64decode(auth[1]).decode("UTF8").split(':') Python 3中base64的结果是字节对象,UTF8是今天使用的默认编码。
    【解决方案2】:

    对于已经使用django-rest-framework (DRF) 的用户:

    DRF 有一个 BasicAuthentication 类,它或多或少地执行其他答案中描述的内容(请参阅source)。

    这个类也可以用在“普通”的 Django 视图中。

    例如:

    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
    

    【讨论】:

      【解决方案3】:

      当您执行基本身份验证请求时,您实际上是在将凭据添加到 Authorization 标头中。在传输之前,这些凭据是 base64 编码的,因此您需要在收到时对其进行解码。

      以下代码 sn-p 假定只有一个有效的用户名和密码:

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

      如果您想与User 模型的用户名和密码进行比较,请尝试以下操作:

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

      请注意,后一个版本不是非常安全。例如,乍一看,我可以看到它容易受到timing attacks 的攻击。

      【讨论】:

      • 是的,这应该可以。但不知何故,如果我这样解决它,我认为我走错了路。我有个人指导方针(对我而言)。一个是“不要编写源代码来实现备份”和下一个是“不要编写源代码来实现身份验证”。这个问题之前已经被更多有才华的人解决了,并且已经有几个月以来经过测试的实现。尽管如此,还是感谢您的 sn-p。我虽然实现这个需要更多的代码。
      【解决方案4】:

      可以使用这个库:https://github.com/hirokiky/django-basicauth

      Django 的基本身份验证实用程序。

      文档展示了如何使用它:

      将装饰器应用于 CBV

      要将@basic_auth_requried 装饰器应用于基于类的视图,请使用 django.utils.decorators.method_decorator.

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

      【讨论】:

      • 如何将它应用到管理站点?
      猜你喜欢
      • 2022-06-10
      • 1970-01-01
      • 2020-04-10
      • 2018-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-24
      • 1970-01-01
      相关资源
      最近更新 更多