Лучший метод проверки многоуровневых реляционных зависимостей
Предположим, у вас есть сущности A, B, C и D.
- D относится к C
- C относится к B
- B относится к A
Кроме того, пользователю разрешается работать только с D, если пользователь владеет.
В определенном состоянии приложения вы включаете ссылку на страницу, которая обращается к 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.
Б) Другим решением было бы чтобы сохранить идентификатор D в текущем сеансе в наборе доступных объектов, которые будут использоваться следующей отображаемой страницей.
C) В качестве альтернативы можно каким-то образом зашифровать параметры GET и POST. При каждом запросе страницы первой операцией будет расшифровка параметров запроса. Если операция расшифровки завершится неудачно, доступ будет запрещен.
D) Или, в бесконечности, хэшируйте все ссылки на всех страницах, сохраняйте карту в сеансе, которая связывает хэши с URL-адресами и записывает только хэши на веб-страницы.
E) Наконец, вы могли бы сохранить ссылки на A, B и C в D, ссылки на A и B в C, ссылки на A в B. Таким образом, на каждом уровне можно было бы немедленно найти корневую сущность .
Каково ваше решение в такой ситуации? И почему?
Хотя я включил тег PHP, я не хочу фокусировать этот вопрос на языке. Я был бы рад получить общее предложения. Или решения, которые уже реализованы, например, в слоях ORM.
ОБНОВЛЕНИЕ-1
Наконец, я выбрал D).
Общий принцип:
Убедитесь, что идентификаторы каким-либо образом подчиненных объектов всегда передаются безопасным/надежным способом. Таким образом, чтобы третья сторона не могла изменить свои ценности.
Подробности:
Этот вариант обеспечивает множество преимуществ по дизайну:
Во-первых, идентификаторы или другие параметры связанных страниц никогда не попадают в браузер. Вместо
http://www.myServer.com/?action=1234&entity=D&ID=23
Большинство страниц связывается таким образом
http://www.myServer.com/?forwardHash=78sd7sdf98asd7ad5aa76asa4a465
Все параметры следующей выполняемой страницы полностью хранятся в сеансе пользователя.
Поскольку все параметры страниц хранятся внутри сеанса пользователя, требуется гораздо меньше проверок . В частности, вышеупомянутые проверки реляционных зависимостей больше не используются. Если что-то находится в сеанс, он был помещен с предыдущего шага доверенного диалога .
Более того, можно даже заставить пользователя вызывать только те ссылки, которые доступны на текущей отображаемой странице . Каждый раз, когда они вызывают ссылку, приложение может аннулировать все остальные ссылки на странице. Таким образом, пользователи не смогут открывать страницы в нескольких окнах и думать, что они видят два разных "состояния" приложения. Если они дважды вызовут ссылку, приложение может выдать сообщение об ошибке.
Наконец, один может напрямую установить то, что я бы назвал диалогами подпроцесса: Вы бы запустили диалог, нажав URL-адрес текущей страницы в стеке продолжения в сеансе и открыв шаг диалога редактирования. Пользователь может либо упорядоченно завершить рабочий процесс диалога, либо намеренно отменить его. Ссылка отменить рабочий процесс может автоматически отображаться в качестве опции пользователя, если стек продолжения не пуст.
Сохраняя продолжение в стеке в сеансе, оно полностью изолирован от текущего шага диалога. Шаг диалога даже ничего не знает о своем вызывающем абоненте.
Заключая функциональность в небольшие вызовы менеджера, подпроцесс, наконец, вызывает flowmanAger::finishflow(). Этот вызов извлекает продолжение из стека и перенаправляет браузер на эту страницу - фактически возвращаясь к точке, с которой начался рабочий процесс.
Поскольку мы используем стек продолжений, можно даже запустить подпроцессы, которые подчиненный другим подпроцессам.
2 answers
Очевидным решением было бы следующее: учитывая D, найдите C, затем найдите B и в конечном итоге найдите A. Если цепочка где-то оборвется, доступ к D будет отклонен. К сожалению, для этого требуется - если это тривиально реализовано - 4 доступа к базе данных вместо одного для A.
Я полагаю, что это возможно. Отчасти это зависит от того, что означает "относится к", но, предполагая относительно простую схему, я ожидаю, что вы сможете объединить все четыре таблицы в одном SQL заявление. Если часть цепочки отсутствует, запрос не вернет ни одной строки.
Или я что-то упускаю?
Я не уверен, что понимаю, чего вы хотите достичь, но не можете ли вы использовать опцию A, чтобы проверить, разрешено ли пользователю работать с D только с одним доступом к базе данных?:
SELECT D.*
FROM D
JOIN C
ON C.id = D.cid
JOIN B
ON B.id = C.bid
JOIN A.id = B.aid
WHERE A.ownedBy = @userID
AND D.id = @idToBechecked