@ganbatte

Как защитить от перезаписи данных? Например форму для редактирования открывают два пользователя, и одновременно меняют его?

Я начинающий веб программист, пишу первое приложение в Laravel. В связи с тем что слишком много данных, я практически всё всунул в json формат в mysql, и все данные input беру с этим $request->except("_token").
Где-то десятки input, в одном форме, существует и другие, вот возник такой вопрос, 1 пользователь открывает форму для редактирования, и заполняет пустые поля и сохраняет, а у второго пользователя это форма стояло открытой, и такой приходит и сохраняет с пустыми значениями, всё данные стерлись от первого пользователя, или же одновременно открывают форму, и кто то переопределяет его значения. Какие существуют защиты ? Можно как то сделать, что бы форму редактирования мог открыть только 1 пользователь, или же сделать защиту с помощью времени, если сохранил первый чел, то пишется время сохранения, и когда 2 пользователь хочет сохранить, то сработает, защита, типа выведет сообщение ("До тебя уже сделали запись, сначала посмотрите на него").
  • Вопрос задан
  • 198 просмотров
Пригласить эксперта
Ответы на вопрос 4
Adamos
@Adamos
Как же вы пишете на Ларавеле, если, дав половину ответа на свой вопрос, не можете реализовать вторую половину?
Таблица, в которую пишется, кто и когда открыл данные на редактирование. При сохранении проверяется, тебе ли принадлежит текущая сессия - и удаляется, раз ты сохранил и закончил, либо получаешь отлуп, если сессия не твоя. При открытии - аналогичная проверка и отлуп, если сессия чужая и таймаут по ней не истек.
Ответ написан
Alex_Wells
@Alex_Wells
PHP/TS/Kotlin developer
updated_at... Просто присылайте с фронта при сохранении updated_at и сравнивайте с текущим. В базе больше присланого - не сохраняете документ, опционально отдаете новую версию и показываете.

Веб-сокеты, version + 1, гребаные отдельные таблицы.. Божечки, какой ужас.
Ответ написан
@rPman
У вас два пути для решения этой проблемы
1. (по моему мнению правильный в большинстве случаев) вы средствами онлайн контроля за сессией (когда точность определения, когда пользователь ушел с формы занимает меньше секунды), обычно это достигается с помощью websocket (раньше использовали http rest longpooling), в интерфейсе определяете понятие - захват (либо по команде либо кто первый, обычно чтобы редактировать, в форму нужно войти в этом режиме, т.е. на странице долджно быть два режима - просмотр и редактирование) и освобождение формы (при сохранении или закрытии) и блокировать кнопки остальным пользователям или давать механизмы отъема прав на правку вплодь до чата или банально высвечивать номер телефона того клиента, который заблокировал форму.

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

2. при нажатии сохранить идет проверка, было ли изменение данных с момента открытия формы, и если да - предупредить об этом, загрузить измененные данные и предложить пользователю поправить. Это реализовать проще, но нужно хорошо подумать над интерфейсом пользователя, особенно если такие коллизии подразумевают быть частыми, чтобы разработчиков потом операторы не пришли бить тапками, так как такое поведение будет раздражать. например дать возможность пользователю на форме ввести данные, которые он только что туда вводил, после того как они будут сброшены загруженными данными, в идеале 1 кликом или хотя бы показывать цветом отличающиеся данные.

Оба подхода имеют место быть и выбор зависит от собственно задачи и что и как часто будут вводить пользователи в таком режиме. Если такие коллизии исключительная редкость, то однозначно второй способ самый простой и логичный, если же коллизии - часть рабочего процесса, то лучше реализовать первый способ.
Ответ написан
@xfg
Данную проблему решают оптимистической блокировкой.

Оптимистическая блокировка не ограничивает модификацию обрабатываемых данных сторонними сессиями, однако перед началом предполагаемой модификации запрашивает значение некоторого выделенного атрибута каждой из строк данных (обычно используется наименование VERSION и целочисленный тип с начальным значением 0). Перед записью модификаций в базу данных перепроверяется значение выделенного атрибута, и если оно изменилось, то транзакция откатывается или применяются различные схемы разрешения коллизий. Если значение выделенного атрибута не изменилось — производится фиксация модификаций с одновременным изменением значения выделенного атрибута (например, инкрементом) для сигнализации другим сессиям о том, что данные изменились.
(с) Википедия

То есть в базе заводите поле version, его вытаскиваете вместе с остальными данными. Затем при обновлении UPDATE SET ..., version = version + 1 WHERE ... AND version = version.

Соответственно если оба загрузили одну и ту же версию документа, то у второго обновление не пройдет, так как версия документа изменилась и от базы будет возвращено 0 изменений. На эту ситуацию кидаем что-то вроде throw ConcurrencyUpdateConflict, а дальше как-либо обрабатываем пытаясь пересохранить еще раз уже с учетом обновлений от предыдущего пользователя и тогда второй пользователь ничего о конфликте не узнает или же уведомляем его, что произошел конфликт и данные необходимо поправить. Как поступить - зависит от формы. Если несколько раз подряд не получилось автоматически разрешить конфликт, то всё равно в любом случае нужно пользователя уведомлять, что не вышло. Иначе это может крутиться долго.

В Yii вроде такое из коробки есть, а в laravel с ходу google ничего из официальной документации не выдал. Но можно и самому сделать.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы