今回は vue+vue-router+vuex の操作権限についてご紹介します。 vue+vue-router+vuex の操作権限の 注意点 について、実際のケースを見てみましょう。
vuex、vue-router、vuex に基づく権限制御チュートリアル。完全なコード アドレスは https://github.com/linrunzheng/vue-permission-control にあります
次に、シミュレーションしてみましょう一般ユーザーがウェブサイトを開くプロセス全体を段階的に説明します。
まず、ローカルサービスlocalhost:8080を開くことから始めます。開いた後、ログインページに入ることがわかっていますが、判断の根拠は何ですか。
まずトークンです。
ログインしていないユーザーはトークンを取得できません。ログインしているキャラクターの場合、トークンはローカルまたはseesionStorageに保存されます。そのため、ログインするかどうかは、現在のトークン。
トークンにアクセスして操作を容易にするために、vuexと組み合わせることで
/* state.js */ export default { get UserToken() { return localStorage.getItem('token') }, set UserToken(value) { localStorage.setItem('token', value) } } /* mutation.js */ export default { LOGIN_IN(state, token) { state.UserToken = token }, LOGIN_OUT(state) { state.UserToken = '' } }
傍受判定
許可が必要なページに入るトークンなし: ログインページにリダイレクト
以来私たちのルートは ' ' と 404 を含めて動的にマウントされているため、ルートが一致しない場合は、login にリダイレクトされます
router.beforeEach((to, from, next) => { if (!store.state.UserToken) { if ( to.matched.length > 0 && !to.matched.some(record => record.meta.requiresAuth) ) { next() } else { next({ path: '/login' }) } } })
さて、ユーザーは localhost:8080 を開きます。デフォルトの一致は '' パスです。現時点ではルートをマウントしておらず、トークンがないため、ログインすることにしました。
ユーザー名とパスワードを入力すると、ストアを介してトークンを設定するための *commit('LOGIN_IN')* が実行されます。
しかし、ルートはまだありません。現時点では、ログイン ルートしかありません
/* 初始路由 */ export default new Router({ routes: [ { path: '/login', component: Login } ] }) /* 准备动态添加的路由 */ export const DynamicRoutes = [ { path: '', component: Layout, name: 'container', redirect: 'home', meta: { requiresAuth: true, name: '首页' }, children: [ { path: 'home', component: Home, name: 'home', meta: { name: '首页' } } ] }, { path: '/403', component: Forbidden }, { path: '*', component: NotFound } ]
現在のユーザーのトークンに基づいて権限を取得するには、バックグラウンドに移動する必要があります。
権限には非常に多くのロジックがあるため、権限を処理するための権限モジュールが vuex に追加されました。
既存のルートリストがあるかどうかを判断するには、vuexのpermissionモジュールに状態permissionListを保存する必要があります。permissionListがnullでない場合は、すでにルートが存在します。働ければならない。
router.beforeEach((to, from, next) => { if (!store.state.UserToken) { ... } else { /* 现在有token了 */ if (!store.state.permission.permissionList) { /* 如果没有permissionList,真正的工作开始了 */ store.dispatch('permission/FETCH_PERMISSION').then(() => { next({ path: to.path }) }) } else { if (to.path !== '/login') { next() } else { next(from.fullPath) } } } })
store.dispatch('permission/FETCH_PERMISSION') が何をするのか見てみましょう
actions: { async FETCH_PERMISSION({ commit, state }) { /* 获取后台给的权限数组 */ let permissionList = await fetchPermission() /* 根据后台权限跟我们定义好的权限对比,筛选出对应的路由并加入到path=''的children */ let routes = recursionRouter(permissionList, dynamicRouter) let MainContainer = DynamicRoutes.find(v => v.path === '') let children = MainContainer.children children.push(...routes) /* 生成左侧导航菜单 */ commit('SET_MENU', children) setDefaultRoute([MainContainer]) /* 初始路由 */ let initialRoutes = router.options.routes /* 动态添加路由 */ router.addRoutes(DynamicRoutes) /* 完整的路由表 */ commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes]) } }
まず、await fetchPermission() はバックグラウンドで与えられた権限配列を取得します。フォーマットはおおよそ次のとおりです
{ "code": 0, "message": "获取权限成功", "data": [ { "name": "订单管理", "children": [ { "name": "订单列表" }, { "name": "生产管理", "children": [ { "name": "生产列表" } ] }, { "name": "退货管理" } ] } ] }
次に、ベースになります。作成したルーティング配列に対して、比較およびフィルタリングして、必要なルートを取得します
/* 这里是我们写好的需要权限判断的路由 */ const dynamicRoutes = [ { path: '/order', component: Order, name: 'order-manage', meta: { name: '订单管理' }, children: [ { path: 'list', name: 'order-list', component: OrderList, meta: { name: '订单列表' } }, { path: 'product', name: 'product-manage', component: ProductManage, meta: { name: '生产管理' }, children: [ { path: 'list', name: 'product-list', component: ProductionList, meta: { name: '生产列表' } }, { path: 'review', name: 'review-manage', component: ReviewManage, meta: { name: '审核管理' } } ] }, { path: 'returnGoods', name: 'return-goods', component: ReturnGoods, meta: { name: '退货管理' } } ] } ] export default dynamicRoutes
比較のために、再帰関数を作成し、この関数に基づいて結果を取得します。 want
/** * * @param {Array} userRouter 后台返回的用户权限json * @param {Array} allRouter 前端配置好的所有动态路由的集合 * @return {Array} realRoutes 过滤后的路由 */ export function recursionRouter(userRouter = [], allRouter = []) { var realRoutes = [] allRouter.forEach((v, i) => { userRouter.forEach((item, index) => { if (item.name === v.meta.name) { if (item.children && item.children.length > 0) { v.children = recursionRouter(item.children, v.children) } realRoutes.push(v) } }) }) return realRoutes }
get 配列をフィルタリングした後、パス「
{ path: '', component: Layout, name: 'container', redirect: 'home', meta: { requiresAuth: true, name: '首页' }, children: [ { path: 'home', component: Home, name: 'home', meta: { name: '首页' } }, <!-- 将上面得到的东西加入到这里 --> ... ] }
」を持つ子に追加します。現時点では、パス「」を持つ子は左側のナビゲーション メニューであり、後で使用するために状態のサイドバーメニューに保存されます。子に追加した後、DynamicRoutes をルートに追加できます。
/* 动态添加路由 */ router.addRoutes(DynamicRoutes) /* 初始路由 */ let initialRoutes = router.options.routes /* 合并起来,就是完整的路由了 */ commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes])
ルートが追加された後、つまりアクション操作が完了したら、action.then で next({ path: to.path }) を呼び出してルートに入ることができます。ここで、パラメータが next に渡されることに注意してください。 , これはルーティング情報を入力するページですが、次のパラメータを渡した後は、現在入力しているルートが廃止され、同じルートですが、主にこれが入力されます。 addRoutes が確実に有効になるようにします。
ルーティングを入力したら、左側のメニューの生成を開始する必要があります。これは以前にsidebarMenuに保存しましたが、再帰ルーティングの場合は、要素のナビゲーションメニューを使用します。自分たちでカプセル化する必要があります。ここでのコアはコンポーネントの名前です。コンポーネント内に子がある場合は、再度自分自身を使用してツリー構造全体のルーティングをたどります。
<template> <p class="menu-container"> <template v-for="v in menuList"> <el-submenu :index="v.name" v-if="v.children&&v.children.length>0" :key="v.name"> <template slot="title"> <i class="iconfont icon-home"></i> <span>{{v.meta.name}}</span> </template> <el-menu-item-group> <my-nav :menuList="v.children"></my-nav> </el-menu-item-group> </el-submenu> <el-menu-item :key="v.name" :index="v.name" @click="gotoRoute(v.name)" v-else> <i class="iconfont icon-home"></i> <span slot="title">{{v.meta.name}}</span> </el-menu-item> </template> </p> </template> <script> export default { name: 'my-nav', props: { menuList: { type: Array, default: function() { return [] } } }, methods: { gotoRoute(name) { this.$router.push({ name }) } } } </script>
ページを更新した後、router.beforeEach の判断に従って、トークンはあるが許可リストが存在しないと、ルートを取得するためのアクションが再トリガーされますので、心配する必要はありません。ただし、ナビゲーション メニューのアクティブ効果は消えます。ただし、el-menu-item のキーをルートの名前に設定しているため、更新後の afterEach で現在のルートの名前を el-menudefault-active に割り当てるだけで済みます。同様に、ブレッドクラム ナビゲーションは、afterEach ステージで一致するすべてのルートを取得することで実現できます。
if (!store.state.permission.permissionList) { store.dispatch('permission/FETCH_PERMISSION').then(() => { next({ path: to.path }) }) } ... router.afterEach((to, from, next) => { var routerList = to.matched store.commit('setCrumbList', routerList) store.commit('permission/SET_CURRENT_MENU', to.name) })
退出登陆后,需要刷新页面,因为我们是通过addRoutes添加的,router没有deleteRoutes这个api,所以清除token,清除permissionList等信息,刷新页面是最保险的。
最后还有一点,每次请求得带上token, 可以对axios封装一下来处理
var instance = axios.create({ timeout: 30000, baseURL }) // 添加请求拦截器 instance.interceptors.request.use( function(config) { // 请求头添加token if (store.state.UserToken) { config.headers.Authorization = store.state.UserToken } return config }, function(error) { return Promise.reject(error) } ) /* axios请求二次封装 */ instance.get = function(url, data, options) { return new Promise((resolve, reject) => { axios .get(url, data, options) .then( res => { var response = res.data if (response.code === 0) { resolve(response.data) } else { Message.warning(response.message) /* reject(response.message) */ } }, error => { if (error.response.status === 401) { Message.warning({ message: '登陆超时,请重新登录' }) store.commit('LOGIN_OUT') window.location.reload() } else { Message.error({ message: '系统异常' }) } reject(error) } ) .catch(e => { console.log(e) }) }) } export default instance
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上がvue+vue-router+vuex 操作権限の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。