Я создаю простой API, используя django-tastypie. Идея в том, что у меня есть два ресурса:
- Ресурс Note, представляющий заметку, оставленную пользователем. Только пользователь, создавший заметку, может редактировать ее.
- Ресурс Комментарий. Комментарии к любой заметке может оставлять любой пользователь.
TL;DR: я не могу ограничить редактирование заметки создателем заметки, но при этом разрешить любому пользователю комментировать заметку.
Я использую следующую настройку для аутентификации:
class CreatedByEditAuthorization(Authorization):
def is_authorized(self, request, object=None, **kwargs):
return True
def apply_limits(self, request, object_list):
if request and request.method != 'GET' and hasattr(request, 'user'):
return object_list.filter(created_by=request.user)
return object_list
Короче говоря, пользователю разрешено редактировать только те объекты, для которых он равен свойству created_by (он может редактировать только созданные им объекты).
Это связано следующим образом:
class NoteResource(ModelResource):
comments = fields.ToManyField('myapp.api.resources.CommentResource', 'comments', null=True, blank=True)
created_by = fields.ToOneField('account.api.resources.UserResource', 'created_by')
def obj_create(self, bundle, request, **kwargs):
return super(HapResource, self).obj_create(bundle, request, created_by=request.user)
class Meta:
queryset = Note.objects.all()
allowed_methods = ['get', 'put', 'post']
authorization = CreatedByEditAuthorization()
поэтому здесь, когда создается объект, я автоматически привязываю текущего пользователя к атрибуту created_by
и привязываю его к соответствующей авторизации.
Ресурс Comment
прост и имеет только ресурсы от ForeignKey
до Note
.
Проблема заключается в следующем: если пользователь А создает заметку, а пользователь Б пытается прокомментировать эту заметку, deliciouspie отправляет (или имитирует) запрос POST для редактирования этой заметки. Эта попытка отклонена, так как пользователь Б не создал примечание, поэтому создать комментарий не удается.
Вопрос в следующем: есть ли способ:
- Предотвратить использование deliciouspie POST для создания обратной связи с ресурсом Note или
- Изменить схему авторизации, чтобы заметки мог редактировать только их создатель, а комментарии можно было создавать вообще?
Заранее спасибо за любую информацию.
Редактировать: у меня есть большой лайфхак, который может это сделать. Я вполне уверен, что это безопасно, но я не уверен; Я попробую построить несколько запросов, чтобы убедиться. Вместо того, чтобы использовать fields.ForeignKey
в Comment
для связи с Note
, я создаю настраиваемое поле:
class SafeForeignKey(fields.ForeignKey):
def build_related_resource(self, value, request=None, related_obj=None, related_name=None):
temp = request.method
if isinstance(value, basestring):
request.method = 'GET'
ret = super(SafeForeignKey, self).build_related_resource(value, request, related_obj, related_name)
request.method = temp
return ret
Каждый раз, когда мы пытаемся создать этот связанный ресурс, мы помечаем запрос как GET
(поскольку мы ожидаем, что он будет соответствовать запросу SELECT
, а не UPDATE
, который соответствует PUT
или POST
). Это действительно уродливо и потенциально небезопасно при неправильном использовании, и я надеюсь на лучшее решение.
Редактировать 2: Насколько я могу судить из исходного кода deliciouspie, нет способа отфильтровать авторизацию по запросу, который фактически будет отправлен.