如何在vue-router之前运行某些东西

时间:2018-12-10 10:19:22

标签: vuejs2 vuex vue-router

我正在建立我的第一个SPA,并且遇到一些问题。它是这样设计的:

  1. Laravel和Laravel视图处理与登录和注册相关的页面。
  2. SPA从登录页面的用户开始。
  3. 我的app.js定义了一个默认的VueJS应用程序,其中我使用mounted()方法来设置已登录用户的状态(VUEX)。理想情况下,它要做的就是通过对Laravel后端的axios调用获取用户详细信息,并填充VUEX状态。
  4. 我在路线定义中使用beforeEnter()方法,以确保只有授权人员才能导航到路线。

这是我面临的问题。当用户登录时,似乎在设置vuex之前已执行路由器。假设我有一个网址/ dashboard和/ user / 1。当我尝试转到user / 1时,如果在加载应用程序之后它可以完美运行。但是,如果我处于用户1状态时刷新网页,则路由器beforeEnter无法找到用户的vuex状态,因此它将用户重定向到仪表板。这是因为,当路由器运行beforeEnter时,如果是全新页面加载,则它将无权访问用户Vuex状态或具有访问权,但尚未设置该值。

因为这个最大的问题是我无法直接链接到路线页面,因为它始终位于仪表板中,因此用户必须转到该路线才能工作。我该如何处理这种情况?

2 个答案:

答案 0 :(得分:1)

这就是我最终要做的。我定义了一个用来初始化Vue的函数。

在app.js的结尾,我使用Axios通过Ajax检索当前用户。在promise的then方法中,我用在promise中收到的用户详细信息设置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']),
    });
}

答案 1 :(得分:0)

我将$ root用作总线,最后转而使用VueX,这是我正在使用的插件中剥离的一些代码,我对其稍加修改,以方便您使用。 。,应该让你走。

此配置支持VUE Cli。

不用担心会话过期,拦截器将监视Laravel发出的401响应,以提示用户重新进行身份验证。

放弃bootstrap.js中的axios配置,并用此设置替换它,并配置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 它将仅在更改时而不是在每个请求时都传递回新的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'
            }
        }
    ]
});