gpt4 book ai didi

Django 从另一个基于类的混合调用基于类的混合

转载 作者:行者123 更新时间:2023-12-05 05:19:17 24 4
gpt4 key购买 nike

我的代码有两个 mixin,BasicAuthMixinJWTAuthMixin,如下所述。假设 self.authenticate 方法返回 True 并且没有引发任何异常:

from django.http import JsonResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View

class BasicAuthMixin(View):

"""
Add this mixin to the views where Basic Auth is required.
"""
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
try:
self.authenticate(request)
except:
return JsonResponse({'status': 403, 'message': 'Forbidden'}, status=403, content_type='application/json')
return super(BasicAuthMixin, self).dispatch(request, *args, **kwargs)

class JWTAuthMixin(View):
"""
Add this mixin to the views where JWT based authentication is required.
"""
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
try:
self.authenticate(request)
except:
return JsonResponse({'status': 403, 'message': 'Forbidden'}, status=403, content_type='application/json')
return super(JWTAuthMixin, self).dispatch(request, *args, **kwargs)

根据所需的身份验证,这些 mixin 正在 View 中使用。

实际问题从这里开始:我正在尝试创建另一个 mixin AllAuthMixin,当包含在任何 View 中时,它将自动确定需要根据哪些 mixin 调用提供的身份验证 header :

class AllAuthMixin(View):

@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
auth = request.META.get('HTTP_AUTHORIZATION') or ''
if auth.startswith('Bearer'):
return JWTAuthMixin.as_view()(request, *args, **kwargs)
elif auth.startswith('Basic'):
return BasicAuthMixin.as_view()(request, *args, **kwargs)
raise Exception('Unauthorized Access to Saurav APIs', 403)

一旦我在任何 View 中包含 AllAuthMixin/test 它实际上调用适当的 Mixins 但返回 Method Not Allowed (GET):/test

我调试并发现如果我使用基本身份验证,Method Not Allowed 错误消息来自下面一行:

return super(BasicAuthMixin, self).dispatch(request, *args, **kwargs)

以下说明了一个非常简单的示例,该示例使用基本身份验证调用我的 View :

>>> import requests
>>> requests.get('http://127.0.0.1:8000/test', auth=('UserName', 'Password'))
<Response [405]>

我不确定我在这里做错了什么。任何人都可以帮我解决问题或任何替代方法来实现这一目标。我想要的是重新使用已经声明的 mixins:BasicAuthMixn 和 JWTAuthMixin。

最佳答案

这里有一个设计问题,两个 mixin 都是通过拦截 dispatch 方法和调用 super 来实现的。您还通过调用 dispatch 来实现 AllAuthMixin 的方式意味着您需要将它们都放在其 MRO 中并“欺骗” super 选择一个合适的,但不是一个好主意。

另一种实现 AllAuthMixin 的方法是不调用 dispatch 而是在它们上实例化并调用 authenticate:

class AllAuthMixin(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
auth = request.META.get('HTTP_AUTHORIZATION') or ''
try:
if auth.startswith('Bearer'):
JWTAuthMixin().authenticate(request) # raises on failed auth
elif auth.startswith('Basic'):
BasicAuthMixin().authenticate(request)
except:
raise Exception('Unauthorized Access to Saurav APIs', 403)

return super(AllAuthMixin, self).dispatch(request, *args, **kwargs)

重用代码的更好方法是将身份验证分离到它自己的类中,并创建使用它们的单独混合。这样您就可以更好地分离关注点。

类似于:

class BasicAuth(object):
def authenticate(self, request):
# raise if not authed
print("Basic auth")

class JWTAuth(object):
def authenticate(self, request):
# raise if not authed
print("JWT auth")

class AuthMixin(View):
def authenticate(self, request):
raise NotImplementedError('Implement in subclass')

@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
try:
self.authenticate(request)
except:
return JsonResponse({'status': 403, 'message': 'Forbidden'}, status=403)

return super(AuthMixin, self).dispatch(request, *args, **kwargs)

class BasicAuthMixin(BasicAuth, AuthMixin):
pass

class JWTAuthMixin(JWTAuth, AuthMixin):
pass

class AllAuthMixin(AuthMixin):
def authenticate(self, request):
auth = request.META.get('HTTP_AUTHORIZATION') or ''
try:
if auth.startswith('Bearer'):
return JWTAuth().authenticate(request)
elif auth.startswith('Basic'):
return BasicAuth().authenticate(request)
except:
return JsonResponse({'status': 403, 'message': 'Other'}, status=403)

class SomeView(AllAuthMixin, View):
def get(self, request):
return JsonResponse({'status': 200, 'message': 'OK'})

-- 原始答案 --

你正在为 AllAuthMixin 中的每个 mixin 调用 as_view,通过调用 as_view()(request, *args, *kwargs) 你'强制 mixin 响应请求,但由于它没有 get 方法,因此返回 405 Method not allowed as described in the docs .

您应该调用 dispatch 并使 AllAuthMixin 从两个子 mixin 继承以正确地将 self 传递给 dispatch。像这样:

class AllAuthMixin(JWTAuthMixin, BasicAuthMixin):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
auth = request.META.get('HTTP_AUTHORIZATION') or ''
if auth.startswith('Bearer'):
return JWTAuthMixin.dispatch(self, request, *args, **kwargs)
elif auth.startswith('Basic'):
return BasicAuthMixin.dispatch(self, request, *args, **kwargs)
raise Exception('Unauthorized Access to Saurav APIs', 403)

class SomeView(AllAuthMixin, View):
def get(self, request):
return JsonResponse({'status': 200, 'message': 'OK'})

关于Django 从另一个基于类的混合调用基于类的混合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46600528/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com