了解Vue中间件管道

通常,在建立SPA时,需要保护某些路线。 例如,假设我们有一个仪表板路由,只有经过身份验证的用户才能访问,我们可以利用auth中间件来确保只有经过身份验证的用户才能访问仪表板路由。

在本教程中,我们将看到如何使用Vue-Router为Vue应用实现中间件管道。

什么是中间件管道?

中间件管道是一堆不同的中间件并行运行。

使用介绍性段落中的假设案例研究,假设我们在/dashboard/movies上有另一个路径,我们只希望订阅用户可以访问。我们已经知道要访问仪表板路由,您需要经过身份验证。

那么,我们如何保护/dashboard/movies路由以确保只有经过身份验证和订阅的用户才能访问该路由?通过使用中间件管道,我们可以将多个中间件链接在一起,并确保它们并行运行。

入门

首先,我们将使用Vue CLI快速搭建新的Vue项目。

vue create vue-middleware-pipeline

安装依赖项

创建并安装项目目录后,导航到新创建的目录并从终端运行以下命令:

npm i vue-router vuex

Vue路由器-是Vue.js的官方路由器

Vuex-是Vue的状态管理库

创建组件

我们的应用程序将包含三个组件。

  • Login—此组件将显示给尚未通过身份验证的用户。

  • 控制板—此组件将显示给已登录的用户。

  • Movies—我们将向已登录并拥有活动订阅的用户显示此组件。

让我们创建这些组件。导航到src/components目录并创建以下文件:Dashboard.vue Login.vueMovies.vue

使用以下代码编辑Login.vue文件:

<template>
  <div>
    <p>This is the Login component</p>
  </div>
</template>

使用以下代码编辑Dashboard.vue文件:

<template>
  <div>
    <p>This is the Dashboard component for authenticated users</p>
    <router-view/>
  </div>
</template>

最后,将以下代码添加到movies.vue文件:

<template>
  <div>
    <p>This is the Movies component for authenticated and subscribed users</p>
  </div>
</template>

创建存储

就Vuex而言,存储只是用于保存应用程序状态的容器。这将允许我们确定用户是否经过身份验证,并检查用户是否已订阅。

src文件夹中,创建一个store.js文件,并将以下代码添加到该文件中:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)


export default new Vuex.Store({
    state: {
        user: {
            loggedIn: false,
            isSubscribed: false
        }
    },

    getters: {
        auth(state) {
            return state.user
        }
    }
})

存储区包含其状态内的用户对象。用户对象包含logged inisSubscribed属性,该属性帮助我们确定用户是否已登录并具有活动订阅我们还在存储中定义了一个getter,它返回用户对象。

定义我们的路线

在创建我们的路由之前,让我们定义它们并关联将附加到每个路由的相应中间件。

/login 除经过身份验证的用户外,其他所有人都可以访问。经过身份验证的用户访问此路由时,应将其重定向到仪表板路由。该路由将guest附加一个中间件。

只有通过身份验证的用户才能访问/dashboard。当未通过身份验证的用户访问此路由时,应该将其重定向到/login路由。我们将把一个验证中间件与此路由关联起来。

/ dashboard / movies仅对经过身份验证和订阅的用户可用。 此路由将受到isSubscribedauth中间件的保护。

创建路由

接下来,在src目录中创建一个router文件夹,然后在该文件夹中创建一个router.js文件。使用以下代码编辑文件:

import Vue from 'vue'
import Router from 'vue-router'
import store from '../store'

import Login from '../components/Login'
import Dashboard from '../components/Dashboard'
import Movies from '../components/Movies'


Vue.use(Router)

const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [
        {
            path: '/login',
            name: 'login',
            component: Login
        },

        {
            path: '/dashboard',
            name: 'dashboard',
            component: Dashboard,
            children: [{
                path: '/dashboard/movies',
                name: 'dashboard.movies',
                component: Movies
            }
        ],
        }
    ]
})


export default router

在这里,我们创建了一个新的router实例,同时传入了两个配置选项和一个route属性,它接受我们前面定义的所有路由。目前,需要注意的是这些路由都没有受到保护。我们很快就会解决这个问题。

接下来,让我们将路由器和存储注入到Vue实例中。使用以下代码编辑src/main.js文件:

import Vue from 'vue'
import App from './App.vue'
import router from './router/router'
import store from './store'

Vue.config.productionTip = false


new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app')

创建中间件

src/router目录中,创建一个中间件文件夹,然后在该特定文件夹下创建guest.jsauth.jsissubscribed.js文件。将以下代码添加到guest.js文件:

export default function guest ({ next, store }){
    if(store.getters.auth.loggedIn){
        return next({
           name: 'dashboard'
        })
    }
   
    return next()
   }

guest中间件检查是否该用户进行身份验证。如果它们通过了身份验证,它们将被重定向到dashboard路由。

接下来,用以下代码编辑auth.js文件:

export default function auth ({ next, store }){
 if(!store.getters.auth.loggedIn){
     return next({
        name: 'login'
     })
 }

 return next()
}

auth中间件中,我们使用存储来检查用户当前是否通过了身份验证。根据用户是否登录,我们要么继续请求,要么将其重定向到登录页面。

使用以下代码编辑isSubscribed.js文件:

export default function isSubscribed ({ next, store }){
    if(!store.getters.auth.isSubscribed){
        return next({
           name: 'dashboard'
        })
    }
   
    return next()
   }

issubscribed中间件类似于auth中间件。使用我们的商店,我们检查用户是否已订阅。如果用户已订阅,则他们可以访问预期的路由,否则将重定向回仪表板页面。

保护线路

既然我们已经创建了所有的中间产品,让我们利用它们来保护我们的路线。使用以下代码编辑src/router/router.js文件:

import Vue from 'vue'
import Router from 'vue-router'
import store from '../store'

import Login from '../components/Login'
import Dashboard from '../components/Dashboard'
import Movies from '../components/Movies'

import guest from './middleware/guest'
import auth from './middleware/auth'
import isSubscribed from './middleware/isSubscribed'


Vue.use(Router)

const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [{
            path: '/login',
            name: 'login',
            component: Login,
            meta: {
                middleware: [
                    guest
                ]
            }
        },

        {
            path: '/dashboard',
            name: 'dashboard',
            component: Dashboard,
            meta: {
                middleware: [
                    auth
                ]
            },
            children: [{
                path: '/dashboard/movies',
                name: 'dashboard.movies',
                component: Movies,
                meta: {
                    middleware: [
                        auth,
                        isSubscribed
                    ]
                }
            }],
        }
    ]
})


export default router

在这里,我们导入了所有的中间件,然后为每个路由定义了一个包含中间件数组的元字段。中间件数组包含我们希望与特定路由关联的所有中间件。

路由器导航保护

Vue路由器提供的导航保护是我们可以使用中间件保护路由的惟一原因。这些导航保护主要用于通过重定向或取消路由来保护路由。

其中一个警卫是全局before警卫,它通常是在路由触发之前调用的钩子。为了注册一个全局before保护,我们在路由器实例上定义了一个beforeEach方法。

const router = new Router({ ... })
router.beforeEach((to, from, next) => {
 //necessary logic to resolve the hook
})

beforeEach方法接收三个参数:

  • to:这是我们要通过的路线。

  • from:这是我们现在出发的路线。

  • next:这是用来解决钩子的函数。

运行中间件

使用beforeach钩子,我们可以运行我们的中间件。

const router = new Router({ ...})

router.beforeEach((to, from, next) => {
    if (!to.meta.middleware) {
        return next()
    }
    const middleware = to.meta.middleware

    const context = {
        to,
        from,
        next,
        store
    }
    return middleware[0]({
        ...context
    })
})

我们首先检查当前正在处理的路由是否具有包含中间件属性的meta字段。 如果找到了中间件属性,则将其分配给const变量。 接下来,我们定义一个上下文对象,其中包含传递给每个中间件所需的一切。

然后,我们在传入上下文对象时将中间件数组中的第一个中间件称为函数。

尝试访问/dashboard路由,您应该被重定向到登录路由。这是因为/src/store.js中的store.state.user.loggedin属性设置为false。将store.state.user.loggedin属性更改为true,您现在应该能够访问/dashboard路由。

我们的中间件现在正在运行,但不是我们想要的那样。 我们的目标是实现一个管道,在该管道中我们可以针对特定的路由运行多个中间件。

return middleware[0]({ …context})

请注意上面代码块中的这一行代码,我们只在meta字段中调用从中间件数组传递来的第一块中间件。 那么,如何确保数组中包含的其他中间件(如果有)也被调用? 这是我们的管道派上用场的地方。

创建管道

导航到src / router目录,然后创建一个middlewarePipeline.js文件。 将以下代码添加到文件中:

function middlewarePipeline (context, middleware, index) {
    const nextMiddleware = middleware[index]

    if(!nextMiddleware){
        return context.next 
    }

    return () => {
        const nextPipeline = middlewarePipeline(
            context, middleware, index + 1
        )

        nextMiddleware({ ...context, next: nextPipeline })

    }
}

Middlewarepipline有三个论点:

  • context:这是我们前面创建的context对象,以便它可以传递到堆栈中的每个中间件。

  • 中间件:这是中间件数组本身,定义在路由的元字段上。

  • index:这是在中间件数组中运行的当前中间件的索引。

const nextMiddleware = middleware[index]
if(!nextMiddleware){
return context.next
}

在这里,我们只需在传递给middlewarepileine函数的索引处取出中间件。如果在该索引中找不到中间件,则返回默认的下一个回调。

return () => {
const nextPipeline = middlewarePipeline(
context, middleware, index + 1
)
nextMiddleware({ ...context, next: nextPipeline })
}

我们在传递上下文时调用nextMiddleware,然后传递nextPipeline const来运行。 重要的是要注意,middlewarePipeline函数是一个递归函数,它将调用自身以获取要在堆栈中运行的下一个中间件,同时将索引增加1。

把这些都放在一起

让我们利用我们的middlewarePipeline。 使用以下代码编辑src / router / router.js文件:

import Vue from 'vue'
import Router from 'vue-router'
import store from '../store'

import Login from '../components/Login'
import Dashboard from '../components/Dashboard'
import Movies from '../components/Movies'

import guest from './middleware/guest'
import auth from './middleware/auth'
import isSubscribed from './middleware/isSubscribed'
import middlewarePipeline from './middlewarePipeline'


Vue.use(Router)

const router = new Router({
    mode: 'history',
    base: process.env.BASE_URL,
    routes: [{
            path: '/login',
            name: 'login',
            component: Login,
            meta: {
                middleware: [
                    guest
                ]
            }
        },

        {
            path: '/dashboard',
            name: 'dashboard',
            component: Dashboard,
            meta: {
                middleware: [
                    auth
                ]
            },
            children: [{
                path: '/dashboard/movies',
                name: 'dashboard.movies',
                component: Movies,
                meta: {
                    middleware: [
                        auth,
                        isSubscribed
                    ]
                }
            }],
        }
    ]
})

router.beforeEach((to, from, next) => {
    if (!to.meta.middleware) {
        return next()
    }
    const middleware = to.meta.middleware

    const context = {
        to,
        from,
        next,
        store
    }


    return middleware[0]({
        ...context,
        next: middlewarePipeline(context, middleware, 1)
    })

})

export default router

在这里,我们使用middlewarepipline运行堆栈中包含的后续middlewares

return middleware[0]({
...context,
next: middlewarePipeline(context, middleware, 1)
})

在调用了第一个中间件之后,使用middlewarePipeline函数,还将调用堆栈中包含的后续中间件,直到不再有可用的中间件为止。

如果您访问/ dashboard / movies路线,则应将您重定向到/ dashboard路线。 这是因为用户当前已通过身份验证,但没有活动的订阅。 将我们商店中的store.state.user.isSubscribeed属性设置为true。 您现在应该可以访问/ dashboard / moviesroute

结论

中间件是保护应用程序中不同路径的一种好方法。这是一个非常简单的实现,说明如何使用多个中间件来保护Vue应用程序中的单个路由。您可以在这里找到github repo的链接。

以上就是了解Vue中间件管道的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » Vue.js 教程