我正在尝试为我的django rest框架视图构建一个权限类,该视图应该允许或禁止用户访问。
class UserPermissions(permissions.DjangoModelPermissions):
"""
"""
def has_object_permission(self, request, view, obj):
# if safe methods (get, retrieve) we check permissions from django perms
if request.method in permissions.SAFE_METHODS:
return super(UserPermissions, self).has_object_permission(request, view, obj)
# else if methods (post, put, patch), we match user with obj and if obj is owner we grant him access
return request.user == obj
上面的代码似乎工作正常,但我正在构建测试用例。我构建了一个案例,我尝试使用用户y凭证有意更新用户x
def test_patching_someones_else_profile(self):
""" Test patching someone's else profile """
response = self.c.post("/api/account/api-token-auth/", {'username': 'lion', 'password': 'password'})
self.assertEqual(response.status_code, 200, "User couldn't log in")
token = response.data['token']
user_id = response.data['id']
header = {'HTTP_AUTHORIZATION': 'Token {}'.format(token)}
response = self.c.patch(reverse('user-detail', args=['1', ]), {'last_name': 'mooz'}, **header)
现在看到的问题,它突然抛出一个异常PermissionDenied(),它不会返回任何status_code来处理,而是应用程序崩溃并跟随异常
======================================================================
ERROR: test_patching_someones_else_profile (dlap.apps.account.tests.UserTestCase)
Test patching someone's else profile
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/mo/Projects/pythonic/dl-env/dlap/apps/account/tests.py", line 217, in test_patching_someones_else_profile
response = self.c.patch(reverse('user-detail', args=['1', ]), {'last_name': 'mooz'}, **header)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/test.py", line 84, in patch
return self.generic('PATCH', path, data, content_type, **extra)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/compat.py", line 487, in generic
return self.request(**r)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/test.py", line 143, in request
return super(APIClient, self).request(**kwargs)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/test.py", line 95, in request
request = super(APIRequestFactory, self).request(**kwargs)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/django/test/client.py", line 444, in request
six.reraise(*exc_info)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/django/core/handlers/base.py", line 139, in get_response
response = response.render()
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/django/template/response.py", line 105, in render
self.content = self.rendered_content
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/response.py", line 59, in rendered_content
ret = renderer.render(self.data, media_type, context)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/renderers.py", line 577, in render
context = self.get_context(data, accepted_media_type, renderer_context)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/renderers.py", line 537, in get_context
raw_data_put_form = self.get_raw_data_form(view, 'PUT', request)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/renderers.py", line 475, in get_raw_data_form
serializer = view.get_serializer(instance=obj)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/generics.py", line 99, in get_serializer
serializer_class = self.get_serializer_class()
File "/Users/mo/Projects/pythonic/dl-env/dlap/apps/account/views.py", line 96, in get_serializer_class
obj = self.get_object()
File "/Users/mo/Projects/pythonic/dl-env/dlap/apps/account/views.py", line 107, in get_object
return super(UserViewSet, self).get_object(queryset=queryset)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/generics.py", line 321, in get_object
self.check_object_permissions(self.request, obj)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/views.py", line 284, in check_object_permissions
self.permission_denied(request)
File "/Users/mo/Projects/pythonic/dl-env/lib/python2.7/site-packages/rest_framework/views.py", line 135, in permission_denied
raise exceptions.PermissionDenied()
PermissionDenied
之前有人遇到过这个问题吗?有没有办法返回403与权限被拒绝消息没有应用程序崩溃?
更新
如下所述,get_seralizer_class()可能导致问题,这正是我面临此错误的原因。但是,我有什么替代方法来构建类似于下面的动态seralizer类方法?
def get_serializer_class(self):
# decide on which seralizer to use
if u'create_guest' in self.action_map.itervalues():
return UserGuestSerializer
if u'create_user' in self.action_map.itervalues():
return PublicUserSerializer
obj = self.get_object()
if self.request.user.id == obj.id:
if u'set_password' in self.action_map.itervalues():
return PasswordSerializer
return PrivateUserSerializer
return PublicUserSerializer
答案 0 :(得分:1)
您似乎正在使用由于某种原因调用.get_serializer_class()
的自定义.get_object()
方法。
File "/Users/mo/Projects/pythonic/dl-env/dlap/apps/account/views.py", line 96, in get_serializer_class
obj = self.get_object()
这导致在呈现Browsable API响应时重新运行每对象权限检查。是否有可能重新考虑您的get_serializer_class
实施?
编辑:请注意,您可以简单地检查self.kargs ['pk'],而不是实际调用get_object。看起来您不需要执行完整的对象检索以进行所有权检查。