主頁 > 企業開發 > Vue前端訪問控制方案

Vue前端訪問控制方案

2021-07-02 06:46:07 企業開發

1、前端訪問控制的常規處理方法

??前端訪問控制,一般針對界面元素dom element進行可見屬性或enable屬性進行控制,有權限的,相關元素可見或使能;沒權限的,相關元素不可見或失能,這樣用戶可以明確哪些是無權訪問的,可見屬性要比使能屬性更廣泛,這是每個dom元素都有的屬性,

??當然前端控制僅僅是整體訪問控制的一部分,后端還需要進一步針對介面訪問進行鑒權,因為通過編輯瀏覽器的界面元素的屬性,可以繞過前端控制,

??在Vue中,也有通過控制路由來實作訪問控制的,但沒有控制界面元素的情況下,用戶體驗不是很好,

??本文給出了Vue框架下前端訪問控制的整體方案,

2、總體方案

??在用戶登錄時,或權限變更時,后端通過介面將權限樹發給前端,為了減少不必要的資料傳輸,后端發出的權限樹僅包括有權限的功能項,即前端收到的權限樹的各個節點都是有權限的功能項,

??權限樹節點的資料部分即為功能項的權限資訊,包括兩個關鍵欄位:url和domKey,url是后端自己使用,在AOP鑒權切面類中,攔截非法的介面訪問,domKey是給前端使用的,即dom element的id值,domKey的確定需要前后端協商一致,不能搞錯,

??domKey在同一個路徑上,不允許重復;不同路徑,允許重復,所謂路徑,是從根節點開始,到該節點的一系列節點組成的樹杈,當然,沒有必要的話,domKey最好不重復,同一個界面視圖范圍的各子節點的domKey也不允許重復,

??前端本地存盤用戶token和權限樹JSON字串,如果本地這個存盤資訊存在,重新打開瀏覽器,可以免登錄,(僅本地token有效,不能完全保證token真的有效,如后端重啟服務器、token過期等導致token失效,前端通過HTTP訪問時,仍然會跳到登錄頁面),

??登錄成功后,將token和權限樹JSON字串保存到本地存盤,

??權限發生變更時,通過response攔截器,檢查有無附加資訊,如有需要,更新token和權限樹JSON字串,

??前端開發一個權限樹的管理的js檔案,用于權限樹JSON物件的訪問,權限樹JSON字串被轉換成權限樹JSON物件,

??開發前端頁面vue檔案時,需要進行權限控制的dom element,使用下列屬性:

 id="相關domKey"

??通過class來標識該界面元素是與訪問控制相關的,目的是確定需要進行權限控制的組件范圍,id即為該功能項對應的domKey,

??然后,使用一個公共權限設定方法,來統一處理權限相關的界面元素,

??由于Vue的組件style,可以有scoped屬性設定,此時,在App.vue中,就不能訪問到相關dom element的class,區域式樣渲染后,在外部被改寫,因此,在scoped限制的情況下,需要在scoped起作用的Vue組件中,也要呼叫公共權限設定方法,另外,scoped的限制,恰好使得相同domKey的節點,可以通過上級節點domKey來加以區分,這樣,就用統一的方法,實作了前端頁面的訪問控制,

3、方案實作

3.1、功能項的表結構定義

DROP TABLE IF EXISTS `function_tree`;
CREATE TABLE `function_tree`
(
  `func_id`       INT(11)      NOT NULL DEFAULT 0 COMMENT '功能ID',
  `func_name`     VARCHAR(100) NOT NULL DEFAULT '' COMMENT '功能名稱',
  `parent_id`     INT(11)      NOT NULL DEFAULT 0 COMMENT '父功能ID',
  `level`         TINYINT(4)   NOT NULL DEFAULT 0 COMMENT '功能所在層級',
  `order_no`	  INT(11)      NOT NULL DEFAULT 0 COMMENT '顯示順序',
  `url`			  VARCHAR(80) NOT NULL DEFAULT '' COMMENT '訪問介面url',
  `dom_key`       VARCHAR(80) NOT NULL DEFAULT '' COMMENT 'dom物件的id',

  `remark`        VARCHAR(200) NOT NULL DEFAULT '' COMMENT '備注',

  -- 記錄操作資訊
  `operator_name` VARCHAR(80)  NOT NULL DEFAULT '' COMMENT '操作人賬號',
  `delete_flag`   TINYINT(4)   NOT NULL DEFAULT 0 COMMENT '記錄洗掉標記,1-已洗掉',
  `create_time`   DATETIME(3)  NOT NULL DEFAULT NOW(3) COMMENT '創建時間',
  `update_time`   DATETIME(3)           DEFAULT NULL ON UPDATE NOW(3) COMMENT '更新時間',
  PRIMARY KEY (`func_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8 COMMENT ='功能表';

??如有需要,可以增加icon欄位,用于前端樹節點的顯示,

3.2、后端權限樹的輸出

??后端在登錄成功后,給前端發送token和權限樹JSON字串,

??關于樹節點的生成,可參閱:Java通用樹結構資料管理---https://www.cnblogs.com/alabo1999/p/14928380.html,里面有關于權限樹的例子,

??為了方便前端管理,這里修改權限樹的輸出,將根節點也一并輸出到前端,

??在管理員修改用戶權限后,動態權限更新,可通過附加資訊,給前端發送token和權限樹JSON字串,參閱:Spring Boot動態權限變更實作的整體方案---https://www.cnblogs.com/alabo1999/p/14948914.html,

3.3、前端本地快取

??vue專案中,新建/src/store目錄,創建inde.js檔案,代碼如下:

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
 
const store = new Vuex.Store({
 
  state: {
    // 存盤token
    token: localStorage.getItem('token') ? localStorage.getItem('token') : '',
    // 存盤權限樹
    rights: localStorage.getItem('rights') ? localStorage.getItem('rights') : ''
  },

  mutations: {
    // 修改token,并將token存入localStorage
    changeLogin (state, user) {
      if(user.token){
        state.token = user.token;
        localStorage.setItem('token', user.token);  
      }
      if (user.rights){
        state.rights = user.rights;
        localStorage.setItem('rights', user.rights);
      }
    }
  }
});
 
export default store;

3.4、創建權限管理模塊

??vue專案中,新建/src/common目錄,創建treeNode.js檔案,代碼如下:

/**
 * 處理樹結構資料,這里主要指功能權限樹
 * 權限樹的結構如下:
 * [
 *   {
 *      nodeData:{
 *          funcId:1,       //功能ID
 *          funcName:"",    //功能名稱
 *          parentId:0,     //父節點ID
 *          level:1,        //功能所在層級
 *          orderNo:2,      //顯示順序
 *          url:"",         //訪問介面url
 *          domKey:""       //dom物件的id
 *      },
 *      children:[
 *          nodeData:{...},
 *          children:[...]
 *      ]
 *   },
 *   {
 *      nodeData:{...},
 *      children:[...]
 *   }
 * ]
 */

 var TreeNode = {
     //功能樹
    rightsTree:null,

     /**
      * 將權限樹的JSON字串加載到樹物件上
      * @param {權限樹的JSON字串} rights 
      */
    loadData(rights){
        //將快取的JSON字串,轉為JSON物件,為一級樹節點的陣列
        var treeNode = JSON.parse(rights);        
        return treeNode;
    },

    /**
     * 在給定樹上,找到上級domkey為superDomkey的給定domKey的樹節點
     * 不同子樹如果存在子節點domKey重復的情況,也可以區分
     * @param {給定樹節點} rightsTree 
     * @param {上級的domkey} superDomkey 
     * @param {樹節點的domkey} domKey 
     */
    lookupNodeByDomkeys(rightsTree,superDomkey,domKey){
        var node = null;
        var superNode = null;
        //先尋找superDomkey
        if(superDomkey != ""){
            //如果上級物件的domkey非空
            superNode = this.lookupNodeByDomkey(rightsTree,superDomkey);
        }
        if (superNode != null){
            //如果上級節點非空,或已找到,則在子樹上搜索,可加快搜索速度,并且可避免子節點domKey重復的情況
            node = this.lookupNodeByDomkey(superNode,domKey);
        }else{
            node = this.lookupNodeByDomkey(rightsTree,domKey);
        }
        return node;
    },

    /**
     * 在給定的子樹中,搜索指定domKey的樹節點
     * @param {子樹} rightsTree 
     * @param {domkey} domKey 
     */
    lookupNodeByDomkey(rightsTree,domKey){
        var node = null;
        var functionInfo = rightsTree.nodeData;
        //先查找自身的資料
        if (functionInfo.domKey == domKey){
            //如果找到,則回傳
            return rightsTree;
        }
        //搜索子節點
        for (var i = 0; i < rightsTree.children.length; i++){
            var item = rightsTree.children[i];
            node = this.lookupNodeByDomkey(item,domKey);
            if (node != null){
                break;
            }
        }

        return node;
    }    
 }

 export default TreeNode;

??如果domKey確保唯一的話,使用Map可能是訪問效率更高的方案,這里還是使用樹型結構來管理權限樹,

3.5、創建公共方法模塊

??vue專案中,在/src/common目錄下,創建commonFuncs.js檔案,代碼如下:

import TreeNode from './treeNode.js'


var commonFuncs =  {
  checkRights(superDomkey){    
    //先加載權限樹
    if (TreeNode.rightsTree == null){
      let rights = localStorage.getItem('rights');
      if (rights === null || rights === ''){
        //沒有權限樹
        return;
      }
      //加載權限樹
      TreeNode.rightsTree = TreeNode.loadData(rights);
    }

    //獲取class包含permissions的所有dom物件
    var elements = document.getElementsByClassName('permissions');
    for(var i = 0; i < elements.length; i++){
      var element = elements[i];
      if (element.id != undefined)
      {
        var node = null;
        //如果物件有id,檢查權限
        if (superDomkey == null || superDomkey == undefined){
          //如果未指定上級domkey,直接查找
          node = TreeNode.lookupNodeByDomkey(TreeNode.rightsTree,element.id);
        }else{
          //指定上級domkey
          node = TreeNode.lookupNodeByDomkeys(TreeNode.rightsTree,superDomkey,element.id)
        }
        if (node != null && node != undefined){
          //包含節點
          if (element.style.display == "none"){
            element.style.display = "";
          }
          console.log('has rights :'+element.id);
        }else{
          element.style.display="none";      
          console.log('has not rights :'+element.id);
        }          
      }          
    }
  }
};

export default commonFuncs;

??checkRights方法,引數為superDomkey,即指定上級節點的domKey,允許為慷訓空串,相當于不指定,其查找當前頁面或scoped范圍的檔案中,class名稱包含permissions的所有dom元素,取得dom的id,即功能節點的domKey,如果在權限樹中存在對應節點,則表示有權限;否則表示無權限,(注意:前端的權限樹都是有權限的功能節點),

3.6、修改main.js

??修改main.js檔案,使得公共模塊生效,代碼如下:

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import md5 from 'js-md5';
import axios from 'axios'
import VueAxios from 'vue-axios'
import TreeNode_ from './common/treeNode.js'
import CommonFuncs_ from './common/commonFuncs.js'
import instance_ from './api/index.js'
import global_ from '../config/global.js'

Vue.use(VueAxios,axios)
Vue.prototype.$md5 = md5
Vue.prototype.TreeNode = TreeNode_
Vue.prototype.$baseUrl = process.env.API_ROOT
Vue.prototype.instance = instance_  //axios實體
Vue.prototype.global = global_
Vue.prototype.commonFuncs = CommonFuncs_

Vue.use(ElementUI)
Vue.config.productionTip = false

/* eslint-disable no-new */
var vue = new Vue({
  el: '#app',
  router,
  store,  
  components: { App },
  template: '<App/>',
  render:h=>h(App)    
})

export default vue

??引入了commonFuncs和TreeNode全域物件,可以在vue檔案中使用,

3.7、組件示例

??側邊導航欄,與權限控制相關,可以作為示例,檔案為Left.vue,代碼如下:

<template>
  <div >
    <el-menu :default-openeds="['1']" style="background:#F0F6F6;">
      <el-submenu index="1">
        <el-menu-item-group > 
          <el-menu-item index="1-1">
            <router-link  tag="li" to="/home" exact-active-
                id="homeMenu" active->
                <i ></i>首頁
            </router-link>
          </el-menu-item>
          <el-submenu index="1-2" id="userManagementMain">
            <template slot="title" ><i ></i>用戶管理</template>
            <el-menu-item index="1-2-1"  id="userManagementSub">
                <router-link  tag="li" to="/userManagement">
                  <i ></i>用戶管理
                </router-link>
            </el-menu-item>
            <el-menu-item index="1-2-2"  id="changePassword">
                <router-link tag="li" to="/changePassword">
                  <i ></i>修改密碼
                </router-link>
            </el-menu-item>            
          </el-submenu>  
          <el-menu-item index="1-3"  id="questionnaireManagement">
            <router-link  tag="li" to="/questionnaireManagement">
              <i ></i>問卷內容管理
            </router-link>
          </el-menu-item>
          <el-submenu index="1-4"  id="issueManagementMain">
            <template slot="title"><i ></i>問卷發布管理</template>
            <el-menu-item index="1-4-1"  id="issueManagementSub">
                <router-link   tag="li" to="/issueManagement">
                  <i ></i>發布問卷查詢
                </router-link>
            </el-menu-item>
            <el-menu-item index="1-4-2"  id="issueTaskQuery">
                <router-link  tag="li" to="/issueTaskQuery">
                  <i ></i>發布任務查詢
                </router-link>
            </el-menu-item>
          </el-submenu>
          <el-menu-item index="1-5"  id="answerSheetManagement">
            <router-link  tag="li" to="/answerSheetManagement">
              <i ></i>答卷管理
            </router-link>
          </el-menu-item>                   
        </el-menu-item-group>
      </el-submenu>
    </el-menu>
  </div>
</template>

<style>
  /* 去掉右邊框 */
  .el-menu {
    border-right: none;
  } 

  .el-submenu {
    background-color: rgb(231, 235, 220) ;
  }  
</style>

??注意那些: id=“XXX”的dom元素,基本都是el-menu-item,這里,將scoped去掉了,因為選單項,目前只有側邊導航欄在使用,

3.7、修改App.vue

??App.vue,作為應用頁面組件的總成,在里面進行總的權限控制,代碼如下:

<template>
  <div id="app">
    <!-- 其他頁 -->
    <el-container style="min-height: calc(100% - 50px);" v-if="$route.meta.keepAlive">
      <!-- 無頭部導航欄 -->
      <el-container>
        <el-aside :style="{width:collpaseWidth}">
          <!-- 側邊欄 -->
          <keep-alive>
            <left></left>
          </keep-alive>
        </el-aside>
        <el-main>
          <!-- Body -->
          <router-view></router-view>
        </el-main>
      </el-container>
      <!-- 無足部 -->
    </el-container>
    
    <!-- 登錄頁 -->
    <router-view v-if="!$route.meta.keepAlive"></router-view>  
  </div>
</template>

<script>
import left from './components/Left.vue'

export default {
  name: 'App',
  components: {
    left: left
  },
  data(){
    return {
      collpaseWidth:200
    }
  },
  mounted:function(){
    this.commonFuncs.checkRights();
  },
  methods: {
    
  }   
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

??在頁面加載時,呼叫commonFuncs.checkRights()方法,進行權限控制,

3.8、測驗一下

3.8.1、獲取權限樹資料

??登錄成功后,后端輸出的權限樹資料如下:

{
	rights = {
		"nodeData": {
			"funcId": 0,
			"funcName": "root",
			"parentId": -1,
			"level": 0,
			"orderNo": 0,
			"url": "",
			"domKey": ""
		},
		"children": [{
			"nodeData": {
				"funcId": 1,
				"funcName": "用戶管理一級選單",
				"parentId": 0,
				"level": 1,
				"orderNo": 0,
				"url": "",
				"domKey": "userManagementMain"
			},
			"children": [{
				"nodeData": {
					"funcId": 3,
					"funcName": "修改密碼",
					"parentId": 1,
					"level": 2,
					"orderNo": 1,
					"url": "/userMan/changePassword",
					"domKey": "changePassword"
				},
				"children": []
			}]
		}, {
			"nodeData": {
				"funcId": 10,
				"funcName": "問卷內容管理一級選單",
				"parentId": 0,
				"level": 1,
				"orderNo": 1,
				"url": "",
				"domKey": "questionnaireManagement"
			},
			"children": [{
				"nodeData": {
					"funcId": 11,
					"funcName": "新增問卷",
					"parentId": 10,
					"level": 2,
					"orderNo": 0,
					"url": "/questionnaireMan/addQuestionnaire",
					"domKey": "addQuestionnaire"
				},
				"children": []
			}, {
				"nodeData": {
					"funcId": 12,
					"funcName": "編輯問卷",
					"parentId": 10,
					"level": 2,
					"orderNo": 1,
					"url": "/questionnaireMan/editQuestionnaire",
					"domKey": "editQuestionnaire"
				},
				"children": []
			}, {
				"nodeData": {
					"funcId": 13,
					"funcName": "查詢問卷",
					"parentId": 10,
					"level": 2,
					"orderNo": 2,
					"url": "/questionnaireMan/queryQuestionnaires",
					"domKey": "queryQuestionnaire"
				},
				"children": []
			}, {
				"nodeData": {
					"funcId": 14,
					"funcName": "復制新建問卷",
					"parentId": 10,
					"level": 2,
					"orderNo": 3,
					"url": "",
					"domKey": "copyAddQuestionnaire"
				},
				"children": []
			}, {
				"nodeData": {
					"funcId": 15,
					"funcName": "瀏覽問卷",
					"parentId": 10,
					"level": 2,
					"orderNo": 4,
					"url": "/questionnaireMan/previewQuestionnaire",
					"domKey": "browseQuestionnaire"
				},
				"children": []
			}, {
				"nodeData": {
					"funcId": 16,
					"funcName": "提交審核",
					"parentId": 10,
					"level": 2,
					"orderNo": 5,
					"url": "/questionnaireMan/submitAduit",
					"domKey": "submitAudit"
				},
				"children": []
			}, {
				"nodeData": {
					"funcId": 18,
					"funcName": "作廢問卷",
					"parentId": 10,
					"level": 2,
					"orderNo": 7,
					"url": "/questionnaireMan/cancelQuestionnaire",
					"domKey": "cancelQuestionnaire"
				},
				"children": []
			}]
		}, {
			"nodeData": {
				"funcId": 20,
				"funcName": "問卷發布管理一級選單",
				"parentId": 0,
				"level": 1,
				"orderNo": 2,
				"url": "",
				"domKey": "issueManagementMain"
			},
			"children": [{
				"nodeData": {
					"funcId": 21,
					"funcName": "發布管理二級選單",
					"parentId": 20,
					"level": 2,
					"orderNo": 0,
					"url": "",
					"domKey": "issueManagementSub"
				},
				"children": []
			}, {
				"nodeData": {
					"funcId": 22,
					"funcName": "發布任務查詢",
					"parentId": 20,
					"level": 2,
					"orderNo": 1,
					"url": "",
					"domKey": "issueTaskQuery"
				},
				"children": []
			}]
		}, {
			"nodeData": {
				"funcId": 40,
				"funcName": "答卷管理一級選單",
				"parentId": 0,
				"level": 1,
				"orderNo": 3,
				"url": "",
				"domKey": "answerSheetManagement"
			},
			"children": [{
				"nodeData": {
					"funcId": 41,
					"funcName": "查詢答卷記錄",
					"parentId": 40,
					"level": 2,
					"orderNo": 0,
					"url": "/answerSheetMan/queryAnswerTask",
					"domKey": "queryAnswerSheet"
				},
				"children": []
			}, {
				"nodeData": {
					"funcId": 42,
					"funcName": "回收記錄明細",
					"parentId": 40,
					"level": 2,
					"orderNo": 1,
					"url": "/answerSheetMan/getAnswerSubmitDetail",
					"domKey": "recoveryDetail"
				},
				"children": []
			}, {
				"nodeData": {
					"funcId": 43,
					"funcName": "答卷統計",
					"parentId": 40,
					"level": 2,
					"orderNo": 2,
					"url": "/answerSheetMan/queryStatResult",
					"domKey": "answerSheetStat"
				},
				"children": []
			}, {
				"nodeData": {
					"funcId": 44,
					"funcName": "答卷原始記錄",
					"parentId": 40,
					"level": 2,
					"orderNo": 3,
					"url": "/answerSheetMan/queryOriginalAnswer",
					"domKey": "queryOriginalAnswer"
				},
				"children": []
			}]
		}]
	}, token = 873820BA39E64005BCCE3E54A830AB2C
}

??這些功能項中,有些與導航欄有關,還有一些是頁面的按鈕或鏈接,在示例中沒有用到,

3.8.2、制作首頁

??制作一個簡單的首頁Home.vue,代碼如下:

<template>
  <div id="home">
    <h4>歡迎使用</h4>
    <h3>XX系統</h3>
  </div>
</template>

3.8.3、簡單設定路由導航檔案

??修改/src/router/index.js檔案,代碼如下:

import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Home from '@/components/Home.vue'
import Login from '@/components/login/Login.vue'

Vue.use(Router)

const router = new Router({
  routes: [
    {
      path: '/home',
      name: 'home',
      component: Home,
      meta: {
        keepAlive: true
       }         
    },
    {
      path: '/login',
      name: 'login',
      component: Login,
      meta: {
        keepAlive: false
       }      
    },    
  ]
})

// 導航守衛
// 使用 router.beforeEach 注冊一個全域前置守衛,判斷用戶是否登陸
router.beforeEach((to, from, next) => {
  if (to.path === '/login') {
    next();
  } else {
    let token = localStorage.getItem('token');
 
    if (token === null || token === '') {
      next('/login');
    } else {  
      if (to.path === '/'){
        next('/home');
      }else{
        next();
      }
    }
  }
});

export default router;

3.8.4、導航欄效果測驗

??現在運行Vue,"npm run dev",然后顯示首頁,并用F12顯示調式資訊:

??側邊欄頁面顯示如下:

??瀏覽器的除錯器的控制臺輸出資訊為:

??說明,domKey為userMangementSub的dom元素沒有操作權限,與側邊欄的效果一致,

3.8.5、scoped情況測驗

??Login.vue,使用了scoped,作為示例,現在將登錄按鈕,進行權限控制,修改如下:

      <el-form-item>
        <el-button type="primary"  id="login" style="width:160px" @click="submitForm('form')">登錄</el-button>
      </el-form-item>

??在Login.vue的script的mounted方法中,增加權限控制代碼:

  mounted:function(){
    //頁面加載時,顯示驗證碼
    this.getVerifyCode();
    this.commonFuncs.checkRights();
  },

??由于domKey為login的,沒有在權限樹中,故其加入權限控制集合,又沒有被授權,則該按鈕應該不可見,

??運行測驗,顯示登錄頁,效果圖如下:

??登錄按鈕不可見了,與預期效果一致,

3.9、登錄成功后保存資訊

??登錄成功后,將后端發生過來的token和權限樹保存起來,并將JSON字串轉為JSON物件,

??代碼如下:

   submitForm(formName) { 
      let _this = this;     
      this.$refs[formName].validate(valid => {
        // 驗證通過為true,有一個不通過就是false
        if (valid) {
          // 通過的邏輯
          let passwd = this.$md5(this.form.password);
          this.instance.userLogin(this.$baseUrl,{
              loginName:_this.form.username,
              password:passwd,
              verifyCode:_this.form.verifyCode
          }).then(res => {
            console.log(res.data);
            if (res.data.code == this.global.SucessRequstCode){
              //如果登錄成功
              _this.userToken = res.data.data.token;
              _this.rights = res.data.data.rights;
              //更新權限樹
              this.TreeNode.rightsTee = this.TreeNode.loadData(_this.rights);
              console.log(this.TreeNode.rightsTee)
              // 將用戶token和權限樹保存到vuex中
              _this.changeLogin({ token: _this.userToken, rights: _this.rights});
              _this.$router.push('/home');
              //alert('登陸成功');
            }else{
              alert(res.data.message);
            }
          }).catch(error => {
            alert('賬號或密碼錯誤');            
            console.log(error);
          });
        } else {
          console.log('驗證失敗');
          return false;
        }
      });
    },

3.10、權限動態更新的攔截處理

??根據權限動態更新方案,管理員修改用戶權限后,該用戶第一次訪問后端介面,回傳資訊中可能會攜帶附加資訊,這個可能在任何回傳JSON格式資料的介面中發生,因此,可使用攔截器,來進行統一處理,

import axios from 'axios';
import router from '../router'
import Vue from 'vue';
import Vuex from 'vuex';
import TreeNode from '../common/treeNode.js'

const instance = axios.create({
  timeout: 60000,
   headers: {
    'Content-Type': "application/json;charset=utf-8"
  }
});

//token相關的response攔截器
instance.interceptors.response.use(response => {  
  if (response) {
    switch (response.data.code) {
      case 3: //token為空
      case 4: //token過期
      case 5: //token不正確    
        localStorage.clear();     //洗掉用戶資訊
        //要跳轉登陸頁
        alert('token失效,請重新登錄!');
        router.replace({
              path: '/login',
        });
        break;
      default:
        break;
    }
    if(response.data.additional){
      //如果包含附加資訊
      var data = https://www.cnblogs.com/alabo1999/archive/2021/07/01/{};
      if(response.data.additional.token){
        //如果包含token
        data.token = response.data.additional.token;
        localStorage.setItem('token', data.token);
      }
      if(response.data.additional.rights) {
        data.rights = response.data.additional.rights;
        localStorage.setItem('rights', data.rights);
        //重繪權限樹
        TreeNode.rightsTree = TreeNode.loadData(data.rights);
      }
    }
  }
  return response;
}, error => {
  return Promise.reject(error.response.data.message) //回傳介面回傳的錯誤資訊
})

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/288801.html

標籤:其他

上一篇:Cesium 拾取 API 完全總結

下一篇:Layui Confirm彈出框連續點擊按鈕會觸發多次事件

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more