首页 文章

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

提问于
浏览
1

我正在 Build 我的第一个SPA,我正面临一些问题 . 这是它的设计方式:

  • Laravel和Laravel Views处理登录和注册相关页面 .

  • SPA从用户登录页面开始 .

  • 我的app.js定义了一个默认的VueJS应用程序,我在其中使用 mounted() 方法设置登录用户的状态(VUEX) . 理想情况下,它所做的只是通过对Laravel后端的axios调用获取用户详细信息并填充VUEX状态 .

  • 我在路线定义中使用 beforeEnter() 方法,以确保只有经过授权的人才能导航到路线 .

这是我面临问题的地方 . 当用户登录时,似乎路由器在设置vuex之前执行 . 假设我有一个url / dashboard和/ user / 1 . 当我尝试转到user / 1时,如果它是在我加载应用程序之后它完美地工作 . 但是,如果我在用户/ 1时刷新网页,则路由器 beforeEnter 无法找到用户的vuex状态,因此会将用户重定向到仪表板 . 这是因为当路由器运行 beforeEnter 时,如果它是一个新的页面加载,它还没有设置't have access to the user Vuex state or it has access, but the value isn't .

因此,我最大的问题是我无法直接链接到路由页面,因为它总是落在仪表板中,然后用户必须前往路由才能工作 . 我该如何处理这种情况?

3 回答

  • 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'];
            }
    
            if(response.status === 401) {
                // TODO trigger re-auth prompt
                return;
            }
    
            return response;
    
        },
    
        function (error) {
    
            if(typeof error !== 'object' || !error.response) {
                return Promise.reject(error);
            }
    
            if(error.response.hasOwnProperty('status') && error.response.status === 401) {
    
                router.push({
                    name: 'login'
                });
    
            }
    
            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()
        ]);
    }
    

    创建app / 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'
                }
            }
        ]
    });
    
  • 0

    与仪表板中一样,您应确保在输入任何路径之前获取用户的数据 . 为此,您可以使用全局导航防护 . 这可以在您的应用程序中的任何位置工作,并且可以替换为仪表板路径中的当前逻辑,其中显式地获取用户数据 .

    假设你有一个函数 getUserData ,它通过API获取数据并有两个回调,一个用于成功,一个用于错误:

    // This is your global router
    const router = new VueRouter({ ... })
    
    // This guard gets executed before each navigation. `next` can be called when everything is ok. This will trigger the normal navigation flow.
    router.beforeEach((to, from, next) => {
      getUserData('getUserData', function success (data) {
          // The call worked. Let's say data has a field `user` with all user data.
          // Save user in vuex store
          this.$store.commit('setUser', data.user)
          // continue flow
          next()
      }, function error (response) {
          // That did not work. Perhaps user has been is logged out or server is down...
          switch (response.status) {
              case 500:
                // Handle server error
                break
              case 401: // Unauthorized
                // Redirect to login page
                window.location = '/login'
                break
          }
      })
    })
    

    以下是全球导航卫士的官方文件:https://router.vuejs.org/guide/advanced/navigation-guards.html#global-guards

  • 0

    这就是我最终做的事情 . 我定义了一个初始化Vue的函数 .

    在app.js的最后,我使用Axios通过Ajax检索当前用户 . 在promise的 then 方法中,我将 store 设置为我在promise中收到的用户详细信息,然后调用我为上面的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']),
        });
    }
    

相关问题