zeroWiNNeR
@zeroWiNNeR

Как подключить CSRF токен в vue.js + spring?

Добрый вечер,
начал изучать spring boot, возникла сложность с подключением js, а точнее vue.js. При отправке post, put запросов выдает 403 ошибку (Forbidden).

Также использую шаблонизатор thymeleaf, через отправку форм с теми же запросами всё ок.

Еще хотел бы добавить, что запросы отправляются на другой url (со страницы ./sms.html на ./message), возможно как-то влияет.

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

sms.html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3" lang="en">
    <head>
        <meta charset="UTF-8">
        <title>web service</title>
        <!-- development version, includes helpful console warnings -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/vue-resource@1.5.1"></script>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>

        <meta name="csrf-token" content="{{ csrf_token() }}">

        <meta name="_csrf" content="${_csrf.token}"/>
        <meta name="_csrf_header" content="${_csrf.headerName}"/>

    </head>
    <body>
        <h3>web service</h3>
            <div id="app">
                <p>{{ csrf_field() }}</p>
                <p>{{ message }}</p>
            </div>
            <script src="/js/main.js">{{ csrf_field() }}</script>
            <input type="hidden" name="_token" :value="csrf">

    </body>
</html>


main.js:
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
    xhr.setRequestHeader(header, token);
});

function getIndex(list, id) {
    for (var i = 0; i < list.length; i++ ) {
        if (list[i].id === id) {
            return i;
        }
    }

    return -1;
}

var messageApi = Vue.resource('/message{/id}');

Vue.component('message-form', {
    props: ['messages', 'messageAttr'],
    data: function() {
        return {
            text: '',
            id: ''
        }
    },
    watch: {
        messageAttr: function(newVal, oldVal) {
            this.text = newVal.text;
            this.id = newVal.id;
        }
    },
    template:
        '<div>' +
        '<input type="text" placeholder="Write something" v-model="text" />' +
        '<input type="button" value="Save" @click="save" />' +
        '</div>',
    methods: {
        save: function() {
            var message = { text: this.text };

            if (this.id) {
                messageApi.update({id: this.id}, message).then(result =>
                    result.json().then(data => {
                        var index = getIndex(this.messages, data.id);
                        this.messages.splice(index, 1, data);
                        this.text = '';
                        this.id = ''
                    })
                )
            } else {
                messageApi.save({}, message).then(result =>
                    result.json().then(data => {
                        this.messages.push(data);
                        this.text = ''
                    })
                )
            }
        }
    }
});

Vue.component('message-row', {
    props: ['message', 'editMethod', 'messages'],
    template: '<div>' +
        '<i>({{ message.id }})</i> {{ message.text }}' +
        '<span style="position: absolute; right: 0">' +
        '<input type="button" value="Edit" @click="edit" />' +
        '<input type="button" value="X" @click="del" />' +
        '</span>' +
        '</div>',
    methods: {
        edit: function() {
            this.editMethod(this.message);
        },
        del: function() {
            messageApi.remove({id: this.message.id}).then(result => {
                if (result.ok) {
                    this.messages.splice(this.messages.indexOf(this.message), 1)
                }
            })
        }
    }
});

Vue.component('messages-list', {
    props: ['messages'],
    data: function() {
        return {
            message: null
        }
    },
    template:
        '<div style="position: relative; width: 300px;">' +
        '<message-form :messages="messages" :messageAttr="message" />' +
        '<message-row v-for="message in messages" :key="message.id" :message="message" ' +
        ':editMethod="editMethod" :messages="messages" />' +
        '</div>',
    created: function() {
        messageApi.get().then(result =>
            result.json().then(data =>
                data.forEach(message => this.messages.push(message))
            )
        )
    },
    methods: {
        editMethod: function(message) {
            this.message = message;
        }
    }
});

var app = new Vue({
    el: '#app',
    template: '<messages-list :messages="messages" />',
    data: {
        messages: [],
    }
});


Просьба помочь разобраться, ещё нашел решение в виде такого пакета: https://www.npmjs.com/package/vue-csrf. Но пока не стал его использовать, т.к. не хотелось бы пока что касаться сборщиков (npm, yarn).
Был бы рад примеру с готовых проектов, где csrf настроен и работает со спрингом.
  • Вопрос задан
  • 74 просмотра
Решения вопроса 1
@azerphoenix
Здравствуйте!
Конкретно с Vue.JS мне не приходилось работать, но сталкивался со случаем, когда нужно использовать CSRF токен с JS (jquery и т.д.).
Вот, ссылки, которые помогли мне в свое время:
https://www.codesandnotes.be/2015/02/05/spring-sec...
Обратите внимание на заголовок
Handling CSRF tokens on the client side

https://www.baeldung.com/csrf-thymeleaf-with-sprin...

https://stackoverflow.com/questions/37383730/how-t...

https://www.baeldung.com/spring-security-csrf

https://stackoverflow.com/questions/33125598/how-t...

https://stackoverflow.com/questions/48985293/sprin...

https://blog.netgloo.com/2014/09/28/spring-boot-en...

Надеюсь, что эти ссылки помогут и Вам.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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