Ajax POST не будет работать с Spring Security _csrf, но метод GET работает - PullRequest
0 голосов
/ 07 мая 2018

Я пытаюсь отправить данные, используя метод jquery ajax post, но пока мне не удалось это сделать.Я использую Spring Security 4.0.4.RELEASE и Spring Framework 4.2.5.RELEASE.После стольких тонн поисков того, почему GET работает, а POST нет.Я обнаружил, что токен _csrf имеет отношение к тому, почему метод POST не разрешен.Я пытаюсь добавить токен по URL, затем он разрешает метод POST, но он получает нулевое значение для всех данных, которые передаются в параметр данных.Вот мой пример кода.

Контроллер:

@RequestMapping(value = "/ajaxAddDeliveryType", method = RequestMethod.GET, produces = "application/json")
    @ResponseBody
    public JsonResponse addDeliveryType(
            @ModelAttribute(value = "delivery") DeliveryType deliveryType,
            BindingResult result) {

        System.out.println("deliveryType "+deliveryType.toString());

        JsonResponse res = new JsonResponse();

        /* Validate all the input. it return "SUCCESS" or "FAIL" status */
        jsonResponse(res, result, deliveryType);

        if (res.getStatus().equalsIgnoreCase("success")) {
            /*
             * If result status is Success insert the data into database
             */
            deliveryTypeService.saveDeliveryType(deliveryType);
        }

        return res;
    }


/*
     * This method will validate all input field in form and returning response.
     * If result has error detected it will set the status to "FAIL". If no
     * error occured in result it will set the status to "SUCCESS".
     */
    public JsonResponse jsonResponse(JsonResponse res, BindingResult result,
            DeliveryType deliveryType) {

        /* Set error message if text field is empty */

        ValidationUtils.rejectIfEmptyOrWhitespace(result,
                "mainte_delivery_type", "Delivery type can not be empty");

        ValidationUtils.rejectIfEmptyOrWhitespace(result, "delivery_weight",
                "Delivery weight not be empty");

        ValidationUtils.rejectIfEmptyOrWhitespace(result, "delivery_price",
                "Delivery price can not be empty.");

        if (!deliveryTypeService.isDeliveryTypeUnique(deliveryType.getId(),
                deliveryType.getMainte_delivery_type())) {

            /* Set status to fail */
            res.setStatus("FAIL");

            /* Set error message if delivery type already exist */
            result.rejectValue("mainte_delivery_type",
                    "Delivery type already exists. Please fill in different value");

            res.setResult(result.getAllErrors());

        }

        if (result.hasErrors()) {

            /* Set status to fail */
            res.setStatus("FAIL");

            /*
             * Collect all error messages for text field that not properly
             * assign value
             */
            res.setResult(result.getAllErrors());

        }

        /* Validate if the weight or price is more than zero / 0 */
        else if (deliveryType.getDelivery_price().toString()
                .equalsIgnoreCase("0")
                || deliveryType.getDelivery_weight().toString()
                        .equalsIgnoreCase("0")) {

            /* Set status to fail */
            res.setStatus("FAIL");

            /* Set error message if delivery type already exist */
            result.rejectValue("delivery_price",
                    "Delivery weight/price value should be more than '0'");

            res.setResult(result.getAllErrors());

        }

        else {

            deliveryTypes.clear(); /* Clear array list */
            deliveryTypes.add(deliveryType);
            /*
             * Add employee model object into list
             */
            res.setStatus("SUCCESS"); /* Set status to success */
            res.setResult(deliveryTypes); /* Return object into list */

        }

        return res;
    }

Консольный вывод при отправке ajax POST метод:

> deliveryType DeliveryType [id=0, mainte_delivery_type=null, delivery_price=null, delivery_weight=null]

Консольный вывод при отправке ajax GET метод:

deliveryType DeliveryType [id=0, mainte_delivery_type=test, delivery_price=123, delivery_weight=12]

Код Javacript:

/*
 * This function will validate all the input field inside the form and return a
     * response if result got an error. otherwise if no error in result is found it
     * will insert the data into database
     */
    function validateAndInsertUsingAjax(action, message) {

        /* Disable button to prevent redundant ajax request */
        $("#btnDeliveryType").prop('disabled', true);


        var datastring = $("#myform").serialize();

        $.ajax({

            type : "GET",
            url : myContext + '/' + action+ '?_csrf=' + $("#token").val(),
            data : datastring,
            contentType : "application/json; charset=utf-8",
            datatype : "json",
            crossDomain : "TRUE",
            success : function(response) {
                var stringResponse = JSON.stringify(response)
                // we have the response

                console.log("response " + stringResponse);

                var obj = JSON.parse(stringResponse);

                if (obj.status == "SUCCESS") {
                    /*
                     * Enable button to make ajax request again after response
                     * return
                     */
                    $("#btnDeliveryType").prop('disabled', false);

                    var userInfo = "<ol>";

                    for (i = 0; i < obj.result.length; i++) {

                        /* Create html elements */

                        userInfo += "<br><li><b>Delivery Type</b> : "
                                + obj.result[i].mainte_delivery_type;

                        userInfo += "<br><li><b>Delivery weight (kg)</b> : "
                                + obj.result[i].delivery_weight;

                        userInfo += "<br><li><b>Delivery Price</b> : "
                                + obj.result[i].delivery_price;

                    }

                    userInfo += "</ol>";

                    /* Draw message in #info div */
                    $('#info').html(message + userInfo);

                    /* Show and hide div */
                    $('#error').hide('slow');
                    $('#info').show('slow');

                    /* Populate DataTable */
                    populateDataTable();

                    /* Hide modal */
                    $('#modalAddDeliveryType').modal('hide');

                } else {
                    /*
                     * Enable button to make ajax request again after response
                     * return
                     */
                    $("#btnDeliveryType").prop('disabled', false);

                    var errorInfo = "";

                    for (i = 0; i < response.result.length; i++) {

                        errorInfo += "<br>" + (i + 1) + ". "
                                + response.result[i].code;

                    }

                    /* Show error message from response */
                    $('#error').html(
                            "Please correct following errors: " + errorInfo);

                    /* Show and hide div */
                    $('#info').hide('slow');
                    $('#error').show('slow');

                }

            },

            /* xhr.status shows server respond */
            error : function(xhr, desc, err) {
                /*
                 * Enable button to make ajax request again after response return
                 */

                $("#btnDeliveryType").prop('disabled', false);
                if (xhr.status == 500) {
                    alert('Error: ' + "Server not respond ");
                }
                if (xhr.status == 403) {
                    alert('Error: ' + "Access Denied");
                }

            }

        });

    }

Страница JSP:

<div class="modal fade" id="modalAddDeliveryType" tabindex="-1"
        role="dialog" aria-labelledby="exampleModalCenterTitle"
        aria-hidden="true">
        <div class="modal-dialog modal-dialog-centered" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h3 class="modal-title" id="exampleModalLongTitle"></h3>
                    <button type="button" class="close" data-dismiss="modal"
                        aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>

                <input type="hidden" id="token" name="${_csrf.parameterName}"
                            value="${_csrf.token}" />

                <!-- Form Text field -->
                <form:form method="GET" modelAttribute="delivery" name="myform"
                    id="myform">
                    <form:input type="hidden" path="id" id="id" />
                    <div class="modal-body">

                        <!-- Input Delivery type -->
                        <div>
                            <label for="mainte_delivery_type">Delivery type: </label>
                            <form:input path="mainte_delivery_type" id="mainte_delivery_type"
                                class="form-control" placeholder="Delivery type" />
                            <form:errors path="mainte_delivery_type" cssClass="error" />
                        </div>

                        <!-- Input Delivery weight -->
                        <div>
                            <label for="delivery_weight">Delivery weight (kg): </label>
                            <form:input type="number" min="0" path="delivery_weight"
                                id="delivery_weight" class="form-control"
                                placeholder="Delivery weight(kg)" />
                            <form:errors path="delivery_weight" cssClass="error" />
                        </div>

                        <!-- Input Delivery price -->
                        <div>
                            <label for="delivery_price">Delivery price: </label>
                            <form:input type="number" min="0" path="delivery_price"
                                id="delivery_price" class="form-control"
                                placeholder="Delivery price" />
                            <form:errors path="delivery_price" cssClass="error" />
                        </div>




                        <div id="error" class="error"></div>

                    </div>

                    <div class="modal-footer">

                        <!-- Close button -->
                        <button type="button" class="btn btn-secondary"
                            data-dismiss="modal">Close</button>

                        <!-- Register button -->
                        <input type="submit" class="btn btn-primary" value="Save"
                            id="btnDeliveryType" onClick="insertOrUpdateDeliveryType()" />

                    </div>
                </form:form>
            </div>
        </div>
    </div>

Я надеюсь, что кто-нибудь предоставит мне лучший способ реализовать этот метод POST.Я новичок в весенней безопасности.

1 Ответ

0 голосов
/ 10 мая 2018

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

Итак, токены CSRF являются случайными, если не сказать больше, и привязаны к сеансам. Это как включение файла cookie в каждую отправляемую вами форму, и запросы GET также должны включать их, пока выполняется действие.

Предполагая, что вы не пытаетесь совершить здесь что-либо вредоносное и имеете полный контроль над своим ботом, вы можете легко отправить начальный запрос GET на веб-сайт, установить сеанс и получить свой токен CSRF, уникальный для вашего сеанса, из HTML-кода. (будет вставлено как значение в тег * <input>).

РЕДАКТИРОВАТЬ: Кстати, если вы контролируете сайт назначения (тот, который генерирует этот токен CSRF!), То, очевидно, вы можете внести в белый список себя или отправить эту информацию специально пользователю через AJAX. Есть способы обойти это, если это так.

...