2017-10-06 165 views
2

我的代码有两个mixin,BasicAuthMixinJWTAuthMixin如下所述。姑且认为self.authenticate方法返回并不会引发任何异常:Django调用基于Mixin的另一个类基于Mixin

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) 

这些混入在根据需要的认证的意见被使用。

的实际问题,从这里开始:我试图创建另一个混入AllAuthMixin,其中包括在任何视图中会自动决定哪些混入需要被称为基于认证报头时提供:

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) 

一旦我有AllAuthMixin在任何观点说/测试它实际上调用适当的混入,但返回不允许的方法(GET):/测试

我调试,发现不允许的方法错误消息从以下行来,如果我使用基本身份验证:

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

以下说明了一个非常简单的例子来叫我的看法与基本身份验证:

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

我不知道我在做什么错在这里。任何人都可以请帮我找出问题或任何其他方式来实现这一点。我想要的是重用已经声明的mixin:BasicAuthMixn和JWTAuthMixin。

回答

2

这里有一个设计问题,这两个mixins都是通过拦截dispatch方法并调用super来实现的。你实施AllAuthMixin的方式也叫dispatch意味着你需要让他们都在其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'}) 

- 原来的答复 -

你打电话as_viewAllAuthMixin每个混合料搅拌,通过调用as_view()(request, *args, *kwargs)你勉强地混入向响应请求,但由于它没有get方法,所以返回405方法不允许,如in the docs所述。

你应该打电话dispatch,也使从两个孩子混入AllAuthMixin继承正确地传递给selfdispatch。像这样:

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'}) 
+0

让我们[继续聊天讨论](http://chat.stackoverflow.com/rooms/156110/discussion-between-saurav-kumar-and-yeray-diaz-diaz)。 –

+0

**调度**每个mixin的方法正在做很多我在这里没有提到的事情;如验证,引发异常,以适当的响应代码返回适当的json响应。不调用调度方法,导致我在** AllAuthMixin **中写入重复代码。但那很好! **你最近的建议起作用**,至少我不打扰现有的代码。非常感谢您宝贵的时间。非常感谢 :) –