Vueで権限制御を実現する方法の例

12134 ワード

はじめに
広告マシンのプロジェクトでは、キャラクターの権限管理は長い間、難しい点です。まず決定した権限の制御は二つの大部分に分けられます。ここでは粒の大きさによってより細かく分けられます。
1、インターフェースアクセスの権限制御
2、ページのパーミッション制御
  • メニューのページは
  • にアクセスできますか?
  • ページのボタン(増減、削除、変更)の権限制御は
  • を表示するかどうか
    これらの権限制御はどのように実現されているかを確認します。
    二、インターフェースアクセスの権限制御
    インターフェースの権限はユーザーに対する検証です。正常には、ユーザがログインする時に、サーバーはフロントにTokenを返す必要があります。その後、フロントでインターフェースを呼び出すたびに、このTokenを持参してサービス側でこのTokenを取得してマッチングします。もし通過すればアクセスできます。
    既存のやり方はログイン成功のフィードバックでバックグラウンドから戻ってきたTokenを直接session Strag eに格納しますが、要求時にTokenを取り出してheadersに入れてバックグラウンドに伝えます。コードは以下の通りです。
    
    this.$http({
         method: 'get',
         url: 'test/query?id=20',
         withCredentials: true,
         headers: {
          token: sessionStorage.getItem('token'),
          name: sessionStorage.getItem('name')  //          
         }
        }).then(response => {
         //        
        })
    
    その後、いくつかの文章の中でaxiosはスクリーンショットの中で直接にTokenをconfig.headers.Authorzationに押し込むことができ、全体として伝わってきた。コード部分は以下の通りです。
    
    //main.js
    import axios from 'axios'
    
    //    Axios,       
    const service = axios.create({
      timeout: 5000
    })
    // baseURL
    // axios.defaults.baseURL = 'https://api.github.com';
    
    // http request    
    //       http   Authorization  ,    token
    service.interceptors.request.use(
      config => {
        if (store.state.user.token) {
          config.headers.Authorization = `token ${store.state.user.token}`;
        }
        return config
      },
      err => {
        return Promise.reject(err)
      }
    );
    export default service
    
    
    三、ページ権限制御
    前に述べましたが、ページの権限制御はまた二つに分けられます。
  • 1メニューのページは
  • にアクセスできますか?
  • 2ページのボタン(増減、削除、変更)の権限制御は
  • を表示するかどうか
    これらの権限は通常、固定ページで設定され、保存してデータベースに記録されます。
    ボタンの権限はともかく、ページアクセス権限は実装中に2つの方法に分けることができます。
  • 1は、すべてのメニューを表示し、ユーザが自分の権限内のメニューにアクセスすると、提示権限が
  • に足りないということです。
  • 2は、現在のユーザがアクセスできる権限内メニューのみを表示し、ユーザがURLを介して強制的にアクセスすると、404
  • に直接アクセスすることができる。
    見せたら注文できないなら、いくつかの意味を込めて、私を笑わせてください。目が見えないということは、総合的に考えてみると、案二がいいユーザー体験に合っているに違いない。
    はい、大体のページアクセス権限の流れを整理します。
    ここに画像の説明を挿入します。
    流れを整理し終わったら、詳しく書き始めます。
    1、ルーティングテーブルの作成
    ルートテーブルを作成するのは実際には難しくないです。vue-routerの公式文書の例をそのまま書いてください。しかし、一部のページにはアクセス権限が必要ではないので、登録、404、メンテナンスなどのページをデフォルトのルートに書く必要があり、他の必要な権限のページを変数またはファイルに書くことで、後続のメンテナンス圧力を効果的に軽減することができる。
    以下はindex.jsのコードを貼り付けて、非同期のルートは適量を減らして、多すぎる紙幅を占めないようにします。
    
    // router/index.js
    import Vue from 'vue'
    import Router from 'vue-router'
    import App from '@/App'
    import store from '../store/index'
    
    Vue.use(Router);
    
    //          
    const whiteList = [
     '/'
    ];
    //          
    const constantRouterMap = [
     {
      path: '/',
      name: '  ',
      component: (resolve) => require(['@/components/login'], resolve)
     },
     {
      path: '/index',
      name: 'nav.Home',
      component: (resolve) => require(['@/components/index'], resolve)
     },
     {
      path: '/templateMake',
      name: '    ',
      component: (resolve) => require(['@/components/Template/templateMake'], resolve)
     },
     {
      path: '/programMack',
      name: '    ',
      component: (resolve) => require(['@/components/Template/programMack'], resolve)
     },
     {
      path: '/release',
      name: '    ',
      component: (resolve) => require(['@/components/Program/release'], resolve)
     }
    ]
    
    //    
    export const router = new Router({
     routes: constantRouterMap
    });
    
    //    (       )
    export const asyncRouterMap = [
    
     {
      path: '/resource',
      name: 'nav.Resource',
      meta: {
       permission: []
      },
      component: (resolve) => require(['@/components/Resource/resource'], resolve)
     },
     {
      path: '/template',
      name: 'nav.Template',
      meta: {
       permission: []
      },
      component: (resolve) => require(['@/components/Template/template'], resolve)
     },
     {
      path: '/generalSet',
      name: 'nav.System',
      meta: {
       permission: []
      },
      component: (resolve) => require(['@/components/SystemSet/generalSet'], resolve)
     },
     {
      path: '',
      name: 'nav.Log',
      component: App,
      children: [
       {
        path: '/userLog',
        name: 'nav.UserLog',
        meta: {
         permission: []
        },
        component: (resolve) => require(['@/components/Log/userLog'], resolve),
       },
       {
        path: '/operatingLog',
        name: 'nav.SystemLog',
        meta: {
         permission: []
        },
        component: (resolve) => require(['@/components/Log/operatingLog'], resolve),
       },
      ]
     }
     ]
    ];
    
    
    注意事項:ここで注意すべき点があります。404ページは最後にロードしなければなりません。もしconstantRouterMapに置いて404を宣言したら、後ろのページは全部404にブロックされます。詳細な問題はaddRoutes when you've got a wildcard route for 404 s does not workに会います。
    2、ページアクセス権限
    開始時に私たちは大体のページアクセス権限の流れを整理しました。次に私達はまず核心の部分を実現します。
    まずユーザー権限のリストを取得します。ここでvuex状態管理に触れます。公式文書に詳しく紹介されています。ここでは説明しただけです。コードを見てください。
    
    // store/index.js
    import Axios from 'axios'
    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex);
    const axios = Axios.create();
    
    const state = {
     mode: 'login',
     list: []
    };
    
    const getters = {};
    
    const mutations = {
     setMode: (state, data) => {
      state.mode = data
     },
     setList: (state, data) => {
      state.list = data
     }
    };
    
    const actions = {
     //       
     getPermission({commit}) {
      return new Promise((resolve, reject) => {
       axios({
        url: '/privilege/queryPrivilege?id=' + sessionStorage.getItem('privId'),
        methods: 'get',
        headers: {
         token: sessionStorage.getItem('token'),
         name: sessionStorage.getItem('name')
        }
       }).then((res) => {
        //       
        commit('setList', res.data.cust.privileges[0].children);
        resolve(res.data.cust.privileges[0].children)
       }).catch(() => {
        reject()
       })
      })
     }
    };
    
    export default new Vuex.Store({
     state,
     mutations,
     actions,
     getters
    })
    
    はい、バックグラウンドに権限データを取得してもらい、データをvuexに保存してください。次にデータマッチングの前に書かれた非同期のルーティングテーブルを利用して、マッチング結果と静的なルーティングテーブルを結合して、最終的な実際のルートテーブルにする必要があります。
    その中で最も重要なのは、Vue-router 2.2.0のバージョンを利用して新しく追加されたaddRoutesの方法です。公式文書を見て、この方法をどう説明しますか?router.addRoutes(routes) 2.2.0+より多くのルーティングルールを動的に追加します。パラメータはロutesのオプションに適合する配列でなければなりません。
    私たちは今からaddRoutesを使ってルートマッチングを開始できます。コードを見ます
    
    // router/index.js
    /**
     *         
     * @param {array} permission     (    )
     * @param {array} asyncRouter       
     */
    function routerMatch(permission, asyncRouter) {
     return new Promise((resolve) => {
      const routers = [];
      //     
      function createRouter(permission) {
         //         router     routers   
       permission.forEach((item) => {
        if (item.children && item.children.length) {
         createRouter(item.children)
        }
        let path = item.path;
        //       ,             routers 
        asyncRouter.find((s) => {
         if (s.path === '') {
          s.children.find((y) => {
           if (y.path === path) {
            y.meta.permission = item.permission;
            routers.push(s);
           }
          })
         }
         if (s.path === path) {
          s.meta.permission = item.permission;
          routers.push(s);
         }
        })
       })
      }
    
      createRouter(permission)
      resolve([routers])
     })
    }
    
    
    そしてナビゲーションフックを作成します。
    
    // router/index.js
    router.beforeEach((to, form, next) => {
     if (sessionStorage.getItem('token')) {
      if (to.path === '/') {
       router.replace('/index')
      } else {
       console.log(store.state.list.length);
       if (store.state.list.length === 0) {
         //        ,          
        store.dispatch('getPermission').then(res => {
          //         
         routerMatch(res, asyncRouterMap).then(res => {
           //            addRoutes
          router.addRoutes(res[0]);
          next(to.path)
         })
        }).catch(() => {
         router.replace('/')
        })
       } else {
        if (to.matched.length) {
         next()
        } else {
         router.replace('/')
        }
       }
      }
     } else {
      if (whiteList.indexOf(to.path) >= 0) {
       next()
      } else {
       router.replace('/')
      }
     }
    });
    
    ここに来て、私たちはページへのアクセス権限のコントロールを完了しました。次に、操作ボタンの権限部分について説明します。
    四、データ操作権限
    前のルート構成の中で私達が多く出てきたコードを覚えていますか?
    
    //    (       )
    export const asyncRouterMap = [
    
     {
      path: '/resource',
      name: 'nav.Resource',
      meta: {
       permission: []
      },
      component: (resolve) => require(['@/components/Resource/resource'], resolve)
     },
     {
      path: '/template',
      name: 'nav.Template',
      meta: {
       permission: []
      },
      component: (resolve) => require(['@/components/Template/template'], resolve)
     },
     {
      path: '/generalSet',
      name: 'nav.System',
      meta: {
       permission: []
      },
      component: (resolve) => require(['@/components/SystemSet/generalSet'], resolve)
     },
     {
      path: '',
      name: 'nav.Log',
      component: App,
      children: [
       {
        path: '/userLog',
        name: 'nav.UserLog',
        meta: {
         permission: []
        },
        component: (resolve) => require(['@/components/Log/userLog'], resolve),
       },
       {
        path: '/operatingLog',
        name: 'nav.SystemLog',
        meta: {
         permission: []
        },
        component: (resolve) => require(['@/components/Log/operatingLog'], resolve),
       },
      ]
     }
     ]
    ];
    
    
    各ルートページにmetaフィールドを追加します。routerMatch関数でマッチする詳細な権限フィールドをここに割り当てます。このフィールドは、各ページのrouteオブジェクトにおいて得られます。
    
    asyncRouter.find((s) => {
         if (s.path === '') {
          s.children.find((y) => {
           if (y.path === path) {
             //  
            y.meta.permission = item.permission;
            routers.push(s);
           }
          })
         }
         if (s.path === path) {
          s.meta.permission = item.permission;
          routers.push(s);
         }
        })
    
    次に私達はVueカスタムコマンドを作成して、ページの中で認証が必要な要素を判断します。
    
    <a @click="upload" v-allow="'3'"></a> /* 3         ID,    3      */
    私たちは直接グローバルコマンドを登録して、vnodeを利用してvueにアクセスする方法です。コードは以下の通りです
    
    //main.js
    //      
    Vue.directive('allow', {
     inserted: (el, binding, vnode) => {
      let permissionList = vnode.context.$route.meta.permission;
      if (!permissionList.includes(binding.value)) {
       el.parentNode.removeChild(el)
      }
     }
    })
    
    これで権限制御プロセスは完全に終了しました。
    以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。