Как заставить что-то запускаться до vue-router - PullRequest
0 голосов
/ 10 декабря 2018

Я строю свой первый SPA, и у меня возникли некоторые проблемы.Вот как это сделано:

  1. Laravel & Laravel Views обрабатывают страницы, связанные с входом и регистрацией.
  2. SPA запускается при входе пользователя на страницу.
  3. Myapp.js определяет приложение VueJS по умолчанию, в котором я использую метод mounted() для установки состояния (VUEX) вошедшего в систему пользователя.В идеале все, что он делает, - это получает данные пользователя через Axios-вызов к бэкэнду Laravel и заполняет состояние VUEX.
  4. Я использую beforeEnter() методы в определениях маршрута, чтобы гарантировать, что только авторизованные люди могут перейти к маршруту.

Здесь я сталкиваюсь с проблемой.Когда пользователь входит в систему, кажется, что маршрутизатор выполняется до установки vuex.Скажем, у меня есть URL / панель инструментов и / пользователь / 1.Когда я пытаюсь перейти к пользователю / 1, он отлично работает, если это происходит после загрузки приложения.Но если я обновлю веб-страницу, когда нахожусь в user / 1, то маршрутизатор beforeEnter не сможет найти состояние пользователя vuex, поэтому он перенаправит пользователя на панель мониторинга.Это связано с тем, что когда маршрутизатор запускает beforeEnter, при загрузке новой страницы он не будет иметь доступа к пользовательскому состоянию Vuex или имеет доступ, но значение еще не установлено.

Из-за этого моей самой большой проблемой является то, что я не могу напрямую связываться со страницей маршрута, так как она всегда попадает на панель мониторинга, и тогда пользователю придется идти по маршруту, чтобы он работал.Как я могу справиться с этой ситуацией?

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

Я так и сделал.Я определил функцию, с помощью которой я инициализировал Vue.

В конце app.js я использовал Axios для получения текущего пользователя через Ajax.В методе обещания then я устанавливаю store с пользовательскими данными, полученными в обещании, а затем вызываю функцию, которую я определил для инициализации Vue выше.Таким образом, при инициализации vue пользователь хранилища уже имеет данные.

Изменение кода было очень минимальным, и мне не пришлось менять существующую реализацию axios.

Это моя новая реализация:

Axios.get('/api/user/info')
    .then(response => {
        (new Vue).$store.commit('setUser', response.data);
        initializeVue();
    })
    .catch(error => initializeVue());

function initializeVue()
{
    window.app = new Vue({
        el: '#app',
        router,
        components: {
            UserCard,
            Sidebar,
        },
        methods: mapMutations(['setUser']),
        computed: mapState(['user']),
    });
}
0 голосов
/ 10 декабря 2018

Я использую $ root в качестве шины и обращаюсь к VueX в качестве крайней меры. Вот некоторый код, который я удалил из плагина, над которым я работаю, я немного адаптировал его, чтобы вы просто добавили его в свой код.., Если вам пора.

Эта конфигурация поддерживает VUE Cli.

Не беспокойтесь об истечении сеанса, перехватчик будет следить за ответом 401 от Laravel, чтобы предложить пользователюповторная аутентификация.

Отключите конфигурацию axios в bootstrap.js и замените ее этой настройкой и настройте Access-Control-Allow-Origin, подстановочный знак подойдет для локального устройства.

axios.defaults.withCredentials = true;

axios.defaults.headers.common = {
    'X-Requested-With': 'XMLHttpRequest',
    'X-CSRF-TOKEN': undefined,
    'Access-Control-Allow-Origin': '*'
};

axios.interceptors.response.use(

    function (response) {

        if(response.headers.hasOwnProperty('x-csrf-token')) {
            axios.defaults.headers['X-CSRF-TOKEN'] = response.headers['x-csrf-token'];
        }

        return response;

    },

    function (error) {

        if(typeof error !== 'object' || !error.response) {
            return Promise.reject(error);
        }

            if(error.response.hasOwnProperty('status')) {

                switch(error.response.status) {

                    case 401:
                    case 419:
                        // DO RE-AUTHENTICATE CALL
                        break;

                }

            }

        return Promise.reject(error);

    }

);

Для остальных...

В main.js

data() {
  return {
    user: {},
    authenticating: false
  }
},

computed: {

    isAuthenticated() {
        // Check a credential only an authorized user would have.

        if(this.$router.app.hasOwnProperty('user') === false || this.$router.app.user === null) {
            return false;
        }

        return this.$router.app.user.hasOwnProperty('id');
    }

},

methods: {

    checkAuth: function () {

        this.$set(this.$router.app, 'authenticating', true);

        axios.get('/auth/user').then(response => {

            this.$set(this.$router.app, 'user', response.data.user);

            if (this.$router.app.isAuthenticated()) {

                this.$router.push(this.$router.currentRoute.query.redirect || '/', () => {
                    this.$set(this.$router.app, 'authenticating', false);
                });

            }

        }).catch(error => {

            // TODO Handle error response
            console.error(error);
            this.$set(this.$router.app, 'user', {});

        }).finally(() => {

            this.$set(this.$router.app, 'authenticating', false);

        });


    },

    login: function (input) {

        axios.post('/login', input).then(response => {

            this.$set(this.$router.app, 'user', response.data.user);

            this.$router.push(this.$router.currentRoute.query.redirect || '/');

        }).catch(error => {
            // TODO Handle errors
            console.error(error);
        });

    },

    logout: function () {

        axios.post('/logout').then(response => {

            this.$set(this.$router.app, 'user', {});

            this.$nextTick(() => {
                window.location.href = '/';
            });

        }).catch(error => {
            console.error(error);
        });

    },

}

beforeCreate: function () {

    this.$router.beforeResolve((to, from, next) => {

        if (to.matched.some(record => record.meta.requiresAuth) && !this.$router.app.isAuthenticated()) {

            next({
                name: 'login',
                query: {
                    redirect: to.fullPath
                }
            });

            return;
        }

        next();
    });
}

В Auth / LoginController.php добавить метод

public final function authenticated(Request $request)
{
    return response()->json([
        'user' => Auth::user()
    ]);
}

Создать приложение / Http / Middleware / AfterMiddleware.php Itбудет передавать новый токен CSRF, только когда он изменяется, а не при каждом запросе.Перехватчик axios будет принимать новый токен при обнаружении.

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Cookie;

class AfterMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if(Cookie::get('X-CSRF-TOKEN',false) !== csrf_token())
            return $next($request)->header('X-CSRF-TOKEN',csrf_token());

        return $next($request);
    }
}

Вы можете эффективно заменить статическую форму входа на Vue с помощью этой настройки.

Вот как выглядит настройка маршрутизатора:

new Router({
    mode: 'history',
    routes: [
        {
            path: '/login',
            name: 'login',
            component: AuthLogin,
            meta: {
                requiresAuth: false,
                layout: 'auth'
            }
        },
        {
            path: '/login/recover',
            name: 'login-recover',
            component: AuthLoginRecover,
            meta: {
                requiresAuth: false,
                layout: 'auth'
            }
        },
        {
            path: '/',
            name: 'index',
            component: Dashboard,
            meta: {
                requiresAuth: true,
                layout: 'default'
            }
        },
        {
            path: '/settings',
            name: 'settings',
            component: Settings,
            meta: {
                requiresAuth: true,
                layout: 'default'
            }
        }
    ]
});
...