我在Django-Tastypie中使用自定义身份验证,在身份验证成功时返回用户名和密码。在ModelResource实例中,一旦身份验证成功,用户名和密码就可用:
class TestResource(ModelResource):
class Meta:
queryset = Test.remote_supported.get_all(username,password)
resource_name = 'test'
filtering = {
'id' : ALL,
}
detail_allowed_methods = ['get', 'post', 'patch']
authorization = Authorization()
authentication = MyCustomAuth()
always_return_data = True
def __init__(self, api_name=None):
self.username = None
self.password = None
super(TestResource, self).__init__(api_name)
def is_authenticated(self, request):
auth_result = self._meta.authentication.is_authenticated(request)
if isinstance(auth_result, HttpResponse):
raise ImmediateHttpResponse(response=auth_result)
if not auth_result is True:
raise ImmediateHttpResponse(response=http.HttpUnauthorized())
# this is where I receive the username and password from my custom auth
self.username, self.password = self._meta.authentication.get_credentials()
这段代码显然不起作用,因为那个用户名和密码在Metaclass中不可用,即使是这样,更改它也不会只影响这个实例,而是所有实例,这不是我的意图,因为用户名和密码的范围应该是每个RESTful查询。
这就是我的模型:
class RemoteAuthSupported(models.Manager):
def get_all(self, username, password):
# ... here I do some custom operations with the username and password
return super(RemoteAuthSupported, self).get_query_set()
class Test(models.Model):
objects = models.Manager()
remote_supported = RemoteAuthSupported()
# ... the field declarations follow here ... #
我尝试这样做的原因是我在Django应用程序中使用非ORM数据源,这需要自己的身份验证,但使用相同的用户名和密码。处理此参数从Tastypie ModelResource传递到Django模型的方法是什么?我可能应该在这里提一下,没有用户模型在使用。
答案 0 :(得分:1)
您可以做的是覆盖返回请求资源列表的obj_get_list
方法。此外,您可以将用户名和密码设置为request
对象本身,以便参数通过请求 - 响应路径传送。此外,您需要将queryset
设置为all()
。
def obj_get_list(self, bundle, **kwargs):
original = super(TestResource, self).obj_get_list(bundle, **kwargs)
request = bundle.request
return original.get_all(request.username, request.password)
或者反过来说 - 您可以添加自定义授权来过滤对象列表。 request
属性部分仍然存在。
class MyAuth(Authorization):
def authorized_read_list(self, objects, bundle):
request = bundle.request
return objects.get_all(request.username, request.password)
如果您希望使用queryset
而不仅仅是替换列表端点来模仿get_all
,则可以覆盖get_object_list
。
def get_object_list(self, request):
original = super(TestResource, self).get_object_list(request)
return original.get_all(request.username, request.password)
答案 1 :(得分:0)
我查看了Tastypie文档,看起来以下可能是一个解决方案,尽管是业余的:
class TestResource(ModelResource):
class Meta:
queryset = Test.remote_supported.get_all('dummyusername','dummypassword')
resource_name = 'test'
filtering = {
'id' : ALL,
}
detail_allowed_methods = ['get', 'post', 'patch']
authorization = Authorization()
authentication = MyCustomAuth()
always_return_data = True
def get_object_list(self, request):
"""
This method calls a clone of the queryset declared in the Metaclass.
It is called every time a query is executed.
Here the actual username and password is passed to the model.
"""
return Site.remote_supported.get_all(self.username,self.password)
问题是,查询集声明只发生在Metaclass中一次,而不是每个查询,因此从http请求中获取的用户名和密码无法传递给Meta级别的查询。但是,由于get_object_list()
克隆了声明并使用updates参数值执行实际调用,因此可以完成工作。它对我有用,但我觉得应该有更好的解决方案。