禁用tastypie对特定HTTP方法的基本身份验证以创建用户

时间:2014-07-20 00:57:18

标签: python django authorization tastypie

我正在试验Tastypie和Django,我想知道我能做什么是可能的。让我解释一下......

我有一个自定义用户资源(和模型)作为我的api的一部分。我希望能够通过此资源更新用户。为确保用户只能由其所有者进行更新,我已启用tastypie.authentication.BasicAuthentication(这是通过put_detail方法完成的。)

问题在于我还希望能够通过此资源创建用户,由于您需要登录凭据才能访问BasicAuthentication,因此无法完成此操作。

所以,我觉得我有以下几种选择:

  1. 以某种方式禁用POST请求的身份验证(似乎没有,我已经尝试过了)。
  2. 创建第二个模型资源,该资源不具有任何形式的身份验证,但仅允许POST请求(我已经尝试过这个,但遇到了以下问题)。
    1. 原始模型资源名为user。理想情况下,我希望将第二个资源命名为user/create,但网址永远无法正确解析,因为user模型已将其取消。
  3. 这是我用第二种方法尝试过的......

    class UserResource(ModelResource):
        ...
    
        class Meta:
            resource_name = 'users'
            queryset = CustomUser.objects.all()
            authentication = BasicAuthentication()
            detail_allowed_methods = ['get', 'put']
    
        def put_detail(self, request, **kwargs):
            # stub
            return HttpAccepted('User updated.')
    
    
    class CreateUserResource(ModelResource):
        class Meta:
            resource_name = 'users/create'
            queryset = CustomUser.objects.all()
            # No authentication
            list_allowed_methods = ['post']
    
        def post_list(self, request, **kwargs):
            # stub
            return HttpCreated('User created.')
    

    如果我向api/v1/users/create发帖,则CreateUserResource永远不会对其进行处理,因为tastypie会将其解释为UsersResource的详细视图,然后我会获得404。

    那么,是否有可能改变tastypie搜索其资源网址的顺序?在我的urls.py文件中注册资源的顺序似乎没有什么区别。或者是否有其他建议可能更适合我想要实施的内容?

1 个答案:

答案 0 :(得分:0)

好的,我设法通过覆盖dispatch模型的UserResource方法,使用方法编号1来完成此操作。来自文档[link]:

  
      
  • dispatch做了一堆繁重的工作。它确保:   
        
    • 请求的HTTP方法位于allowed_methods(method_check),
    •   
    • 该类有一个方法可以处理请求(get_list),
    •   
    • 用户已通过身份验证(is_authenticated),
    •   
    • 用户已获得授权(is_authorized),
    •   
    • &安培;用户没有超过他们的油门(throttle_check)。
    •   
  •   
     

此时,dispatch实际调用所请求的方法   (get_list)。

现在,我想绕过is_authenticated步骤,但前提是request是" POST"到“'列表'类型。我的实现代码如下......

from django.http import HttpResponse
from tastypie.http import HttpAccepted, HttpBadRequest, HttpCreated, HttpNoContent, HttpNotImplemented
from tastypie.authentication import BasicAuthentication
from tastypie.exceptions import ImmediateHttpResponse
from tastypie.fields import IntegerField, ToManyField
from tastypie.resources import ModelResource, convert_post_to_put

from <your_user_module> import User    

class UserResource(ModelResource):
    ...

    class Meta:
        resource_name = 'users'
        queryset = User.objects.all()

        authentication = BasicAuthentication()

        list_allowed_methods = ['get', 'post']
        detail_allowed_methods = ['get']

    # Bypasses the authentication process if the request is a
    # POST to the 'list'. The code within the 'if' block is
    # taken from 'tastypie.resources.Resource.dispatch()'
    def dispatch_list(self, request, **kwargs):
        if request.method == 'POST':
            request_type = 'list'
            allowed_methods = getattr(self._meta, "%s_allowed_methods" % request_type, None)

            if 'HTTP_X_HTTP_METHOD_OVERRIDE' in request.META:
                request.method = request.META['HTTP_X_HTTP_METHOD_OVERRIDE']

            request_method = super(UserResource, self).method_check(request, allowed=allowed_methods)
            method = getattr(self, "%s_%s" % (request_method, request_type), None)

            if method is None:
                raise ImmediateHttpResponse(response=HttpNotImplemented())

            # Authentication would normally happen here...
            # ... simply comment it out.
            # super(UserResource, self).is_authenticated(request)
            super(UserResource, self).throttle_check(request)

            # All clear. Process the request.
            request = convert_post_to_put(request)
            response = method(request, **kwargs)

            # Add the throttled request.
            super(UserResource, self).log_throttled_access(request)

            # If what comes back isn't a ``HttpResponse``, assume that the
            # request was accepted and that some action occurred. This also
            # prevents Django from freaking out.
            if not isinstance(response, HttpResponse):
                return HttpNoContent()

            return response
        else:
            return super(UserResource, self).dispatch_list(request, **kwargs)

    # The normally required authentication is bypassed
    # (through the overridden dispatch_list) method above.
    def post_list(self, request, **kwargs):
        # Process the request as usual...    
        return HttpCreated('User created.')