Предположим, у вас есть объекты A, B, C и D.
- D относится к C
- C относится к B
- B относится к A
Кроме того, пользователю разрешено работать только на D , если пользователь владеет A .
В определенном состоянии в приложении вывключить ссылку на страницу, которая обращается к D. Таким образом, вы включаете идентификатор D в качестве параметра GET или POST.
Если пользователь нажимает на ссылку, приложение получает идентификатор D и начинает работать с D.
Простые приложения используют такие URL-адреса, как этот [перезапись URL-адреса по модулю]:
http://www.myServer.com/?action=1234&entity=D&ID=23
Как проверить, разрешено ли пользователю работать с D?
A) Очевидное решение было бы следующим: Учитывая D, найдите C, затем найдите B и в конечном итоге найдите A. Если цепь где-нибудь оборвется, доступ к D будет отклонен.К сожалению, для этого требуется - если тривиально реализовать - 4 доступа к базе данных вместо одного для A.
B) Другое решение - сохранить идентификатор D в текущем сеансе в наборе доступных сущностей, которые будут использоваться на следующей странице для визуализации.
C) В качестве альтернативы можно шифровать параметры GET и POST как-то.При каждом запросе страницы первой операцией будет расшифровка параметров запроса.Если операция дешифрования завершится неудачно, доступ будет запрещен.
D) Или, при бесконечности, хеширует все ссылки на всех страницах , сохраните карту в сеансе,связывает хэши с URL-адресами и записывает только хэши на веб-страницы.
E) Наконец, вы можете сохранить ссылки на A, B и C в D, ссылки на A и B в C, ссылки на A в B. Таким образом, на каждом уровне по одномусмог бы немедленно найти корневую сущность.
Каково ваше решение в такой ситуации?И почему?
Хотя я включил тег PHP, я не хочу фокусировать этот вопрос на языке.Я был бы счастлив получить общие предложения.Или решения, которые уже реализованы, например, в ORM слоях.
UPDATE-1
Наконец, я выбрал D) .
Общий принцип:
Убедитесь, что идентификаторы подчиненных объектов всегда передаются безопасным / доверенным способом.Таким образом, третье лицо не может изменить свои значения.
Подробности:
Этот параметр обеспечивает множество преимуществ по своему дизайну:
Во-первых, идентификаторы или другие параметры связанных страниц никогда не доходят до браузера.Вместо
http://www.myServer.com/?action=1234&entity=D&ID=23
большинство страниц связываются следующим образом
http://www.myServer.com/?forwardHash=78sd7sdf98asd7ad5aa76asa4a465
Все параметры следующей страницы, которая должна быть выполнена, полностью хранятся внутри пользователясеанс .
Поскольку все параметры страниц хранятся в сеансе пользователя, требуется гораздо меньше проверок .В частности, упомянутые выше проверки реляционных зависимостей больше не используются.Если что-то находится в сеансе пользователя, оно было перенесено из ранее доверенного диалогового окна, шаг .
Более того, можно даже заставить пользователя вызывать только те ссылки, которые доступны натекущая страница .Каждый раз, когда они вызывают ссылку, приложение может лишить законной силы все другие ссылки на странице.Таким образом, пользователи не смогут открывать страницы в нескольких окнах и думать, что они видят два разных «состояния» приложения.Если они дважды вызывают ссылку, приложение может выдать сообщение об ошибке.
Наконец, можно напрямую установить то, что я бы назвал sub-workflow диалогов: Вы могли бы начать диалог, нажавURL текущей страницы в стеке продолжения в сеансе и открытии шага диалога редактирования.Пользователь может либо упорядоченно завершать, либо намеренно отменять рабочий процесс диалога. отменить ссылку рабочего процесса может автоматически отображаться как опция пользователя, если стек продолжения не пуст.
Сохраняя продолжение в стеке в сеансе, оно полностью изолируется от текущего шага диалога.Шаг диалога даже не знает ничего о вызывающем.
Обернув функциональность внутри вызовов небольшого менеджера, подпроцесс наконец вызывает FlowManager :: finishFlow ().Этот вызов выдает продолжение из стека и перенаправляет браузер на эту страницу - , фактически возвращаясь к точке, с которой начался рабочий процесс .
Поскольку мы используем стек продолжений, можно даже запускать подпроцессы, подчиненные другим подпроцессам .