MVC 5 ValidateAntiForgeryToken Ajax Post не работает при входе в систему

Фон

Я прочитал много других сообщений на этом сайте с похожими проблемами, но ничего конкретно не связанного с моим. Я также учусь в Uni и пытаюсь применить свое образование к реальным проблемам, чтобы получить более глубокое понимание MVC, но каждый шаг на этом пути был монументальным усилием. (мы изучали Laravel, что было еще сложнее). Это мой первый пост, и я с нетерпением жду вашей помощи.

Проблема

«Вход в систему» ​​останавливает работу сообщений ajax.

У меня есть форма с выпадающими списками, которые заполняются из базы данных. Целью раскрывающихся списков является настройка строки заказа продукта. После изменения раскрывающегося списка он запускает публикацию ajax, которая отправляет детали формы обратно в метод контроллера, который ищет в базе данных строки упорядочивания, которые могут совпадать, и повторно заполняет форму только возможными параметрами на основе выбранной конфигурации.

Это отлично работает при анонимности, но при входе в систему он не пройдет через атрибут [ValidateAntiForgeryToken] на контроллере.

Все в порядке, когда я комментирую атрибут.

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

Я пробовал AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; в Application_Start() безрезультатно.

Если это так, то у меня 2 вопроса:

  1. Как обновить токен при входе в систему?
  2. Если я публикую раскрывающийся контент только через ajax, действительно ли мне нужно использовать токены защиты от подделки? (Я бы предположил, что они требуются для каждого поста).
  3. Нужен ли мне другой атрибут, например: [Авторизация] или [AllowAnonymous]?

Если не так, то что еще я мог посмотреть?

Просмотр (_config.cshtml)

@model HomeWeb.Models.RtcgConfigurationModel

@using (Html.BeginForm("updateDB", "Rtcg", FormMethod.Post, new { enctype =    "multipart/form-data" }))

{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h3>Configure RTCG</h3>
        <hr />
        @Html.ValidationSummary(true)


        <div class="form-group">
            @Html.LabelFor(model => model.RtcgCabinetType, "Cabinet Type", new { @class = "control-label col-md-5" })
            <div class="col-md-7">
                @Html.DropDownListFor(model => Model.RtcgCabinetType, Model.Cabinets, new { onchange = "changed();" })
                @Html.ValidationMessageFor(model => model.RtcgCabinetType)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.RtcgAdaptorType, "Adaptor Type", new { @class = "control-label col-md-5" })
            <div class="col-md-7">
                @Html.DropDownListFor(model => Model.RtcgAdaptorType, Model.Adaptors, new { onchange = "changed();" })
                @Html.ValidationMessageFor(model => model.RtcgAdaptorType)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.RtcgQtyAdaptors, "Adaptor Qty.", new { @class = "control-label col-md-5" })
            <div class="col-md-7">
                @Html.DropDownListFor(model => Model.RtcgQtyAdaptors, Model.AdaptorQtys, new { onchange = "changed();" })
                @Html.ValidationMessageFor(model => model.RtcgQtyAdaptors)
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.RtcgTerminationMethod, "Termination", new { @class = "control-label col-md-5" })
            <div class="col-md-7">
                @Html.DropDownListFor(model => Model.RtcgTerminationMethod, Model.TerminationMethods)
                @Html.ValidationMessageFor(model => model.RtcgTerminationMethod)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.RtcgFaceplateStyle, "Faceplate Style", new { @class = "control-label col-md-5" })
            <div class="col-md-7">
                @Html.DropDownListFor(model => Model.RtcgFaceplateStyle, Model.FacePlateStyles)
                @Html.ValidationMessageFor(model => model.RtcgFaceplateStyle)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.RtcgScreenPrinting, "Screenprinting", new { @class = "control-label col-md-5" })
            <div class="col-md-7">
                @Html.DropDownListFor(model => Model.RtcgScreenPrinting, Model.ScreenPrintOptions)
                @Html.ValidationMessageFor(model => model.RtcgScreenPrinting)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.RtcgApplication, "Fibre Type", new { @class = "control-label col-md-5" })
            <div class="col-md-7">
                @Html.DropDownListFor(model => Model.RtcgApplication, Model.Applications)
                @Html.ValidationMessageFor(model => model.RtcgApplication)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.RtcgVerminProof, "Vermin Proof", new { @class = "control-label col-md-5" })
            <div class="col-md-7">
                @Html.DropDownListFor(model => Model.RtcgVerminProof, Model.VerminProofing)

                @Html.ValidationMessageFor(model => model.RtcgVerminProof)
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-5 col-md-10">
                <input type="submit" value="Get Quotation" class="btn btn-primary" style="float: none"  />
            </div>
        </div>
    </div>
}

<script type="text/javascript">
    function changed() {
        var token = $('[name=__RequestVerificationToken]').val();
        var headers = {};
        headers["__RequestVerificationToken"] = token;
        $.ajax({
            url: '/Rtcg/Ajax_DropdownChanged',
            type: "POST",
            data: $('form').serialize(),
            headers: headers,
            success: function (result) {
                $('#config-form').html(result);
            },
        })

    }
</script>

Контроллер

// POST: handle dropdown changes from Ajax
      [HttpPost]       
      [ValidateAntiForgeryToken]
        public ActionResult Ajax_DropdownChanged(RtcgConfigurationModel formData)
        {  
            //handle 'postback' displaying the fields. 
            if (ModelState.IsValid)
            { 
                RtcgConfigurationModel model = new RtcgConfigurationModel();
                using (var db = new ApplicationDbContext())
                {
                    model.Cabinets = DisplayElement.Cabinets(formData);
                    model.Adaptors = DisplayElement.Adaptors(formData);
                    model.AdaptorQtys = DisplayElement.AdaptorQuantities(formData);
                    model.TerminationMethods = DisplayElement.Termination(formData);
                    model.FacePlateStyles = DisplayElement.Faceplates(formData);
                    model.ScreenPrintOptions = DisplayElement.ScreenPrinting(formData);
                    model.Applications = DisplayElement.Application(formData);
                    model.VerminProofing = DisplayElement.VerminProof(formData);   
                }
                return PartialView("_config", model);
            }
            else
            {
                return View();
            }
        }

ОБНОВЛЕНИЕ

Когда я не вошел в систему, я получаю одну строку токена.

"__RequestVerificationToken = Rt3m8M0YJeJ9u1TENd19Mx6wDxtU6FE208nRAOjo7Py6tkyH_pZdJfgPiXDt70UqJCf_fwasRA_7Ekc792khXWMXDzWS8x3wfXDoWNIZQVQ1 & RtcgCabinetType = RTC2G & RtcgAdaptorType = ЖК & RtcgQtyAdaptors = 06 & RtcgTerminationMethod = FS & RtcgFaceplateStyle = Z & RtcgScreenPrinting = SP & RtcgApplication = SM & RtcgVerminProof = N",

Однако при входе в систему я получаю 2 токена (даже если следую предложению Стивенса ниже и удаляю заголовок).

"__RequestVerificationToken = d21oW7noP0WBLI_3ubvpPo7uHYPbIrsq0VzeIXgNNaxmPiMiA8IBr2N2qU3wepup5X46gpy4VaFDc_MfUhCE-SADGhwplraMk4PFt-72GpnsxTeGW2COOggVhFEAXvRyb_ofh3d-ax3Zc1twpfenUw2 & __ RequestVerificationToken = v0g2f1ukJlO9g1WyXqh6GS3PB_YXHo9rY75BD1Wf8voQFMMbwDFE4nKJRV20orE5nm0EBIj4LOWlo_JdUfFvm2A-364nbEwEdEyHDcJ0tVjmqYTbH1AAorg0b347vSB3KLZ00sulasO9A9_28erP0A2 & RtcgCabinetType = RTC2G & RtcgAdaptorType = LCD & RtcgQtyAdaptors = 06 & RtcgTerminationMethod = FS & RtcgFaceplateStyle = Z & RtcgScreenPrinting = SP & RtcgApplication = SM & RtcgVerminProof = N",


person Chris Duguid    schedule 21.06.2016    source источник
comment
Вам не нужно добавлять headers["__RequestVerificationToken"] = token;- ваш код data: $('form').serialize(), уже сериализует токен и отправляет его в запросе.   -  person    schedule 21.06.2016
comment
Привет Стивен. Спасибо за супер быстрый ответ. При публикации данных формы через ajax атрибут [ValidateAntiForgeryToken] не отображается, если я не публикую токен в заголовке. Я пытался закомментировать их, но это вообще не сработало, вошел в систему или нет.   -  person Chris Duguid    schedule 21.06.2016
comment
Нет необходимости делать это вообще.   -  person    schedule 21.06.2016
comment
Да, я читал противоречивую информацию об этом. К сожалению, у меня нет полного понимания того, как публикуемые данные обрабатываются атрибутом [ValidateAntiForgeryToken]. Если бы вы могли объяснить, как он справляется с этим, с точки зрения непрофессионала, было бы здорово. Конечно, если бы я мог заставить это работать, было бы еще лучше. Есть ли другая область, которая может быть причиной проблемы?   -  person Chris Duguid    schedule 21.06.2016
comment
То, что вы показали (за исключением дублирования токена в заголовке), должно работать нормально, поэтому не уверен, в чем проблема. Какое сообщение об ошибке отображается в ответе (вкладка «Сеть» браузера) при вызове ajax?   -  person    schedule 21.06.2016
comment
@StephenMuecke - я получаю внутреннюю ошибку сервера 500.   -  person Chris Duguid    schedule 21.06.2016
comment
Да, я знаю, но каковы подробности ошибки? (используйте инструменты браузера — вкладку «Сеть», чтобы проверить ответ)   -  person    schedule 21.06.2016
comment
@StephenMuecke - мне нужно извиниться. Вы были правы, он работает без части заголовков (будь я проклят, я провел ночи, пытаясь заставить его работать!!! лол). Мне также пришлось удалить часть заголовков из сообщения ajax. Это вызывало ошибку. Однако проблема все еще остается в том, что он не будет работать при входе в систему. Уверен, что это связано с двумя токенами в сериализованной строке. Интересно узнать, как такое могло произойти. Может ли это быть от другого @Html.AntiForgeryToken(), плавающего в представлении?   -  person Chris Duguid    schedule 21.06.2016
comment
@StephenMuecke — показывает: Не удалось расшифровать маркер защиты от подделки. Если это приложение размещается на веб-ферме или в кластере, убедитесь, что на всех компьютерах работает одна и та же версия веб-страниц ASP.NET и что в конфигурации ‹machineKey› указаны явные ключи шифрования и проверки. AutoGenerate нельзя использовать в кластере.   -  person Chris Duguid    schedule 21.06.2016
comment
Это, вероятно, объясняет это - вы работаете в веб-ферме? Предложите также погуглить mvc Токен защиты от подделки не может быть расшифрован для возможных решений   -  person    schedule 21.06.2016
comment
Если вы имеете в виду несколько серверов в кластере, нет. В настоящее время я просто работаю в Visual Studio на своем компьютере и, как только закончу, развернусь на одном автономном сервере в своем гараже. Надеюсь, я понял ваш вопрос.   -  person Chris Duguid    schedule 21.06.2016
comment
Я предполагаю, что у вас может быть 2 токена. У вашего ajax есть $('#config-form').html(result);, но показанная вами форма не имеет id="config-form", поэтому я предполагаю, что у вас должно быть 2 формы. Предлагаем вам начать с добавления атрибута id к форме, которую вы показали, а затем использовать data: $('#yourID').serialize(),, чтобы обеспечить сериализацию только соответствующей формы.   -  person    schedule 21.06.2016
comment
Вы угадали. Кажется, у меня генерируются несколько токенов. Я удалил их все, кроме одного, и теперь это работает, но я получаю Обязательное поле формы защиты от подделки __RequestVerificationToken отсутствует, когда пытаюсь выйти из системы. Я думаю, что я назову эту проблему решенной и должен поблагодарить вас за вашу помощь. Мне нужно будет повозиться с размещением токена в нужном месте, чтобы дать всему сайту доступ к нему. Спасибо еще раз!!!!   -  person Chris Duguid    schedule 21.06.2016
comment
@StephenMuecke - Не знаю, как поставить вам галочку или пару очков репутации, но я хотел бы сказать спасибо.   -  person Chris Duguid    schedule 21.06.2016


Ответы (1)


Моя проблема заключалась в том, что на моем сайте было несколько @Html.AntiForgeryToken(). Я использовал частичное представление, и оно было объявлено в представлении _LoginPartial, а также в форме, которую я использовал для публикации.

Это вызвало несколько токенов в моем сообщении формы, и оно не прошло проверку.

person Chris Duguid    schedule 21.06.2016