Как обнаружить различия между значениями GET и POST ViewModel в форме?

StackOverflow https://stackoverflow.com/questions/1868525

  •  18-09-2019
  •  | 
  •  

Вопрос

У меня есть единое представление, которое обрабатывает множество моделей типа VoyagesViewModel, в этом представлении пользователь может создать новый рейс или отредактировать все активные рейсы, поэтому у меня есть разные экземпляры одного и того же типа объекта в этом представлении.каждая форма содержит что-то вроде:

<% = Html.Hidden("Voyages["+ i +"].VoyageDetails[" + i2 + "].Id", location.Id)%>
<% = Html.TextBox("Voyages[" + i + "].VoyageDetails[" + i2 + "].ArrivalDate", location.ArrivalDate, new { @class = "dates" })%><% = Html.ValidationMessage("Voyages[" + i + "].VoyageDetails[" + i2 + "].ArrivalDate", "*")%>
<% = Html.TextBox("Voyages[" + i + "].VoyageDetails[" + i2 + "].DepartureDate", location.DepartureDate, new { @class = "dates" })%><% = Html.ValidationMessage("Voyages[" + i + "].VoyageDetails[" + i2 + "].DepartureDate", "*")%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].LocationID", location.LocationID)%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].LocationName", location.LocationName)%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].VesselName", location.VesselName)%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].VesselID", location.VesselID)%>
<% = Html.CheckBox("Voyages[" + i + "].VoyageDetails[" + i2 + "].remove", location.remove)%> (remove)

У меня есть от 8 до 10 из этого в этом представлении, когда пользователь публикует форму (у меня есть все эти поля в одной форме), я хочу иметь возможность определить, изменил ли пользователь что-то в рейсе, чтобы сохранить это, поэтому мне не нужно сохранять этот конкретный рейс, если никаких изменений не было сделано.

Чтобы проверить это, у меня есть скрытое поле, и я делаю это:

 <% = Html.Hidden("Voyages[" + i + "].hash", TamperProofing.GetExpiringHMAC(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model), DateTime.Now.AddMinutes(15)))%>

Я использую HMAC для получения хэшированной версии объекта hole, но сначала я сериализую объект в строковый формат (формат JSON):

{"Id":22,"VesselName":"CAPTAIN P (CPP)","VesselID":8,"VoyageDetails":[{"Id":58,"ArrivalDate":"\/Date(1259298000000)\/","DepartureDate":"\/Date(1259384400000)\/","LocationID":404,"LocationHash":null,"LocationName":"Balboa, Panama (PABLB)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":60,"ArrivalDate":"\/Date(1260248400000)\/","DepartureDate":"\/Date(1260334800000)\/","LocationID":406,"LocationHash":null,"LocationName":"Colon Free Zone, Panama (PACFZ)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":61,"ArrivalDate":"\/Date(1260421200000)\/","DepartureDate":"\/Date(1260507600000)\/","LocationID":407,"LocationHash":null,"LocationName":"Cristobal, Panama (PACTB)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":62,"ArrivalDate":null,"DepartureDate":null,"LocationID":408,"LocationHash":null,"LocationName":"Manzanillo, Panama (PAMAN)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":59,"ArrivalDate":null,"DepartureDate":null,"LocationID":405,"LocationHash":null,"LocationName":"Coco Solo, Panama (PACSO)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":true}],"newVoyageDetail":null,"isComplete":false,"Code":"A Code","position":0,"hash":null}

Поэтому, когда пользователь ПУБЛИКУЕТ форму, я проверяю, были ли внесены изменения в каждый рейс следующим образом:

 var obj = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(_voyage);
     if (TamperProofing.VerifyChanges(obj, hash) == TamperProofing.HMACChanged.True)
    {
       //UPDATE
    }else
    {
       //DO Nothing, is the exact same object
    }

Сериализуйте его снова и сравните оба хэша, тот, что на скрытом, с недавно вычисленным, если он совпадает, это означает, что ничего не изменилось.

Все работает довольно хорошо, мне просто интересно, есть ли какие-либо другие варианты сделать это?

И еще одна моя проблема - это время, которое может занять сериализация и все HMAC-операции с этой большой строкой, сгенерированной сериализацией, по сравнению со временем, которое может потребоваться только для повторного обновления неизмененного объекта в БД.

Редактировать:Мне не нужно знать, какое поле изменилось, просто изменилось ли что-то.

Это было полезно?

Решение

Если вас беспокоит производительность сервера, вы могли бы рассмотреть возможность создания поля "изменено" для каждой записи и использования Javascript для его установки при изменении одного из редактируемых пользователем значений поля.

Чтобы обеспечить корректность в браузерах нижнего уровня или в случаях NoScript fringe, общим шаблоном является использование значения из трех состояний, при этом одно состояние означает "неизвестно" или "JS отключен".Например, вы инициализируете поля на сервере равными 0 (или пустыми), в вашем JS-коде им всем присваивается значение 1 при загрузке, а затем значение 2 при изменении поля.Если ваш сервер видит 0 / null / empty в POST, то он возвращается к серверному методу, в данном случае к вашему хэш-сравнению.Если для него установлено значение 1, то он игнорирует эту запись, а если для него установлено значение 2, то он автоматически запускает обновление.

Таким образом, вы могли бы избежать вычисления хэшей в 99% случаев и при этом корректно обрабатывать выбросы.

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

Помогает ли это вообще?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top