Ошибка аутентификации для MongoEngineResource с помощью ReferenceField

117
13

Запрос во встроенную область MongoEngineResource не проходит процесс аутентификации, если он содержит поле ссылки.

Мое дело следующее:

    существует раздел документа, который состоит из FieldDefinitions FieldDefinitions - это EmbeddedDocuments FieldDefinition содержит embedded_section (необязательно), который ссылается на раздел, и есть сигнал, который исключает саморегуляцию (например, embedded_section может ссылаться только на раздел, который не содержит FieldDefinition) все это часть интерфейса модератора, поэтому я использую авторизацию для всех видов запросов (получение, публикация, исправление и т.д.),

Вот код:

from tastypie_mongoengine.resources import MongoEngineResource
from tastypie.authentication import ApiKeyAuthentication
from apps.api.auth import CustomAuthorization

class FieldDefinitionResource(MongoEngineResource):
embedded_section = ReferenceField(attribute='embedded_section',
to='myproject.apps.api.resources.SectionResource',
full=True, null=True)

class Meta:
object_class = models.FieldDefinition # mongoengine EmbeddedDocument
authentication = ApiKeyAuthentication()
authorization = CustomAuthorization()

class SectionResource(MongoEngineResource):
fields = EmbeddedListField(attribute='fields',
of='myproject.apps.api.resources.FieldDefinitionResource',
full=True, null=True)
class Meta:
object_class = models.Section # mongoengine Document
authentication = ApiKeyAuthentication()
authorization = CustomAuthorization()

Поэтому, когда я прошу детали раздела (например,/api/v1/section/524df40502c8f109b07ed6ae/), все идет гладко, а fields attr отображаются корректно в обоих случаях наличия и отсутствия embedded_section.

Но попытка ссылаться на конкретное поле (например,/api/v1/section/524df40502c8f109b07ed6ae/fields/0/) вызывает ошибку:

error_message: "'AnonymousUser' object has no attribute 'has_permission'"

has_permission - это метод MongoUser, который наследуется от Django auth.User. В первом описанном выше примере (раздел подробно) он проходит проверку подлинности и заполняет request.user соответствующим пользовательским объектом, а во втором случае (поле раздела) он полностью пропускает этап аутентификации, переходя прямо к авторизации.

Я делаю что-то неправильно?

Вот полный отрывок:

{"error_message": "'AnonymousUser' object has no attribute 'has_permission'", "traceback": "Traceback (most recent call last):

File "/var/www/vhosts/myproject/local/lib/python2.7/site-packages/tastypie/resources.py", line 195, in wrapper
response = callback(request, *args, **kwargs)

File "/var/www/vhosts/myproject/local/lib/python2.7/site-packages/tastypie_mongoengine/resources.py", line 277, in dispatch_subresource
return resource.dispatch(request=request, **kwargs)

File "/vagrant/myproject/myproject/apps/api/resources.py", line 248, in dispatch
super(FieldDefinitionResource, self).dispatch(request_type, request, **kwargs)

File "/var/www/vhosts/myproject/local/lib/python2.7/site-packages/tastypie_mongoengine/resources.py", line 776, in dispatch
self.instance = self._safe_get(bundle, **kwargs)

File "/var/www/vhosts/myproject/local/lib/python2.7/site-packages/tastypie_mongoengine/resources.py", line 768, in _safe_get
return self.parent.cached_obj_get(bundle=bundle, **filters)

File "/var/www/vhosts/myproject/local/lib/python2.7/site-packages/tastypie/resources.py", line 1113, in cached_obj_get
cached_bundle = self.obj_get(bundle=bundle, **kwargs)

File "/var/www/vhosts/myproject/local/lib/python2.7/site-packages/tastypie_mongoengine/resources.py", line 528, in obj_get
return super(MongoEngineResource, self).obj_get(bundle=bundle, **kwargs)

File "/var/www/vhosts/myproject/local/lib/python2.7/site-packages/tastypie/resources.py", line 2069, in obj_get
self.authorized_read_detail(object_list, bundle)

File "/var/www/vhosts/myproject/local/lib/python2.7/site-packages/tastypie/resources.py", line 589, in authorized_read_detail
auth_result = self._meta.authorization.read_detail(object_list, bundle)

File "/vagrant/myproject/myproject/apps/api/auth.py", line 201, in read_detail
bundle.request.user.has_permission('read_detail',

File "/var/www/vhosts/myproject/local/lib/python2.7/site-packages/django/utils/functional.py", line 205, in inner
return func(self._wrapped, *args)

AttributeError: 'AnonymousUser' object has no attribute 'has_permission'
"}

спросил(а) 2021-01-25T21:00:29+03:00 4 месяца, 3 недели назад
1
Решение
132

Это известная проблема в django-tastypie-mongoengine: см. Https://github.com/wlanslovenija/django-tastypie-mongoengine/issues/71

https://github.com/wlanslovenija/django-tastypie-mongoengine/issues/72

и https://github.com/wlanslovenija/django-tastypie-mongoengine/issues/70

Эти три проблемы касаются одной и той же проблемы:

Аутентификация выполняется только до самого действия, но не до действий над ресурсом до целевого действия.

Пример (с использованием кода в моем вопросе): целевое действие update_detail экземпляра FieldDefinitionResource, который является дочерним элементом SectionResource. Перед обновлением детали FieldDefinitionResource есть read_detail разделаResource - и это действие, для которого django-tastypie-mongoengine пропускает этап аутентификации. Это приводит к отсутствию request.user, что, в свою очередь, препятствует движению рабочей силы к целевому действию (update_detail дочернего ресурса).

Это относится к EmbeddedDocumentField, EmbeddedListField, ReferencedListField и ReferenceField.

Одним из возможных способов решения проблемы является переопределение авторизации для внедренного/ссылочного документа:

class CustomAuthorization(Authorization):
def read_detail(self, object_list, bundle):

# Double-check anonymous users, because operations
# on embedded fields do not pass through authentication.
if bundle.request.user.is_anonymous():
MyAuthentication().is_authenticated(bundle.request)

# Now authorize.
try:
return bundle.request.user.has_permission(object_list, 'read_detail')
except AttributeError:
raise Unauthorized(_('You have to authenticate first!'))

Но, конечно, было бы неплохо, если бы оно было разрешено в будущих выпусках.

ответил(а) 2021-01-25T21:00:29+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема