Основная проблема
У меня отдыхает API. Для этого примера предположим, что у меня есть пользователи, они могут быть членами в любом количестве групп, и как пользователи, так и группы могут владеть объектами.
Любой пользователь может фильтровать объекты по различным критериям:
/objects?color=green
/objects?created=yesterday
но только члены данной группы могут фильтровать по принадлежности группы:
/objects?groupId=1
и только фактический пользователь может фильтровать по владению пользователем:
/objects?userId=55
Теперь есть два основных шаблона - можно сделать объект дочерним элементом группы, например:
/groups/4/objects/1
где 4 - это идентификатор группы, а 1 - идентификатор объекта. другой вариант - расположить группу и объекты рядом:
/groups/4
и
/objects/1
превращение объекта в дочерний по отношению к группе и / или пользователю устранит другие параметры фильтрации - по сути, у меня есть один объект с несколькими путями к нему.
Актуальный вопрос
Если я хочу ограничить доступ для обычного пользователя, чтобы он мог получить доступ только к объектам, которые принадлежат непосредственно ему / ей или группам, членом которых он / она является, это действительно работает как фильтр для коллекции, но как насчет уровня сущности?
Если я попробую:
/objects/9
Но объект принадлежит группе, членом которой я не являюсь, я бы ожидал ошибки авторизации, а если объект вообще не существует, я ожидал бы «не найден» - это, однако, приведет к утечке информации о о существовании книги, и мне также пришлось бы получить объект, чтобы определить, имеет ли пользователь право его видеть.
Итак, я придумал это:
/objects/9?groupId=4
or
/objects/9?userId=55
В этом случае я могу основывать первоначальное решение об авторизации на идентификаторе группы или пользователя, а затем попытаться получить объект с дополнительным ограничением.
Если пользователь НЕ является членом группы 4
, я могу сказать not authorized
, а если книга не существует, я могу сказать not found
, имея в виду не то, что объект не существует, а то, что объект не существует в группе 4
. Этот ответ более ясен, и мне не нужно сначала извлекать объект.
Альтернативой может быть возврат ошибки авторизации независимо от того, вызвана ли она тем, что я не авторизован, ИЛИ из-за того, что объект не существует. Этот ответ немного неточен, но вызовет меньшую нагрузку на вызывающего абонента.
Другая возможность - отобразить несколько путей:
/objects
/groups/4/objects
/users/9/objects
/colors/green/objects
Это кажется довольно запутанным и нарушит принцип наличия единого пути для единой концепции.
Есть ли у кого-нибудь практическое понимание этого? Какие-либо причины (помимо упомянутых), почему тот или иной вариант предпочтительнее?