摘要:基于的權限控制教程,完整代碼地址見接下來讓我們模擬一個普通用戶打開網站的過程,一步一步的走完整個流程。由于權限這塊邏輯還挺多,所以在添加了一個模塊來處理權限。
基于vuex, vue-router,vuex的權限控制教程,完整代碼地址見 https://github.com/linrunzhen...
接下來讓我們模擬一個普通用戶打開網站的過程,一步一步的走完整個流程。
首先從打開本地的服務localhost:8080開始,我們知道打開后會進入login頁面,那么判斷的依據是什么。
首先是token。
沒有登陸的用戶是獲取不到token的,而登陸后的角色我們會將token存到local或者seesionStorage 因此,根據當前有沒有token即可知道是否登陸。
/* 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 = "" } }攔截的判斷
沒有token進入需要權限的頁面:redirect到login頁面
由于我們路由是動態掛載的,包括 " " 和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,默認匹配的是""路徑,此時我們并沒有掛載路由,也沒有token,所以來到了login。
輸入用戶名密碼后,有token了,通過store觸發 commit("LOGIN_IN") 來設置token。
但是還是沒有路由,目前最開始只有login路由
/* 初始路由 */ 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 } ]我們要根據當前用戶的token去后臺獲取權限。
由于權限這塊邏輯還挺多,所以在vuex添加了一個permission模塊來處理權限。
為了判斷是已有路由列表,需要在vuex的permission模塊存一個state狀態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
為了對比,我寫好了一個遞歸函數,用name和meta.name進行對比 ,根據這個函數就可以得到我們想要的結果
/** * * @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 }
得到過濾后的數組后,加入到path為""的children下面
{ path: "", component: Layout, name: "container", redirect: "home", meta: { requiresAuth: true, name: "首頁" }, children: [ { path: "home", component: Home, name: "home", meta: { name: "首頁" } }, ... ] }這個時候,path為""的children就是我們左側的導航菜單了,存到state的sidebarMenu待用。加入到children后,這時DynamicRoutes就可以加入到路由了。
/* 動態添加路由 */ router.addRoutes(DynamicRoutes) /* 初始路由 */ let initialRoutes = router.options.routes /* 合并起來,就是完整的路由了 */ commit("SET_PERMISSION", [...initialRoutes, ...DynamicRoutes])
路由添加完了,也就是action操作完畢了,即可在action.then里面調用 next({ path: to.path })進去路由,這里要注意, next里面要傳參數即要進入的頁面的路由信息,因為next傳參數后,當前要進入的路由會被廢止,轉而進入參數對應的路由,雖然是同一個路由,這么做主要是為了確保addRoutes生效了。進入路由后,要開始生成左側菜單,之前我們已經存到sidebarMenu了,現在需要做的只是遞歸生成菜單而已,雖然用了element的導航菜單,但是為了遞歸路由,還需要自己封裝一下。這里核心的地方是組件的name,在組件里面有children的地方,又再次使用自己,從而遍歷整個tree結構的路由。
刷新頁面后,根據我們router.beforeEach的判斷,有token但是沒permissionList,我們是會重新觸發action去獲取路由的,所以無需擔心。但是導航菜單active效果會不見。不過我們已經把el-menu-item的key設置為路由的name,那么我們只要在刷新后,在afterEach把當前路由的name賦值給el-menu default-active即可。同理,在afterEach階段獲取所有matched的路由,即可實現面包屑導航。
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
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107744.html
摘要:我們將登錄按鈕上綁上事件,點擊登錄之后向服務端提交賬號和密碼進行驗證。所以前端和后端權限的劃分是不太一致。側邊欄最后一個涉及到權限的地方就是側邊欄,不過在前 完整項目地址:vue-element-admin 系列文章: 手摸手,帶你用vue擼后臺 系列一(基礎篇) 手摸手,帶你用vue擼后臺 系列二(登錄權限篇) 手摸手,帶你用vue擼后臺 系列三 (實戰篇) 手摸手,帶你用vu...
摘要:二接口訪問的權限控制接口權限就是對用戶的校驗。代碼如下按扭權限指令至此為止,權限控制流程就已經完全結束了,在最后我們再看一下完整的權限控制流程圖吧五路由控制完整流程圖六參考文獻手擼后臺管理網站之權限控制手摸手,帶你用擼后臺之權限控制 原文首發于我的博客,歡迎點擊查看獲得更好的閱讀體驗~ 一、前言 在廣告機項目中,角色的權限管理是卡了挺久的一個難點。首先我們確定的權限控制分為兩大部分,其...
摘要:二接口訪問的權限控制接口權限就是對用戶的校驗。代碼如下按扭權限指令至此為止,權限控制流程就已經完全結束了,在最后我們再看一下完整的權限控制流程圖吧五路由控制完整流程圖六參考文獻手擼后臺管理網站之權限控制手摸手,帶你用擼后臺之權限控制 原文首發于我的博客,歡迎點擊查看獲得更好的閱讀體驗~ 一、前言 在廣告機項目中,角色的權限管理是卡了挺久的一個難點。首先我們確定的權限控制分為兩大部分,其...
摘要:二接口訪問的權限控制接口權限就是對用戶的校驗。代碼如下按扭權限指令至此為止,權限控制流程就已經完全結束了,在最后我們再看一下完整的權限控制流程圖吧五路由控制完整流程圖六參考文獻手擼后臺管理網站之權限控制手摸手,帶你用擼后臺之權限控制 原文首發于我的博客,歡迎點擊查看獲得更好的閱讀體驗~ 一、前言 在廣告機項目中,角色的權限管理是卡了挺久的一個難點。首先我們確定的權限控制分為兩大部分,其...
摘要:簡介用動態路由實現權限控制,是一個很的方案不是么初始路由只有登錄頁,根據用戶的查詢對應的權限,然后,將獲取到的菜單數據放入和瀏覽器緩存中。 addRoutes簡介 用動態路由實現權限控制,是一個很nice的方案不是么? 初始路由只有登錄頁,根據用戶的id查詢對應的權限,然后addRoutes,將獲取到的菜單數據放入vuex和瀏覽器緩存中。 動態添加更多的路由規則。參數必須是一個符合 r...
閱讀 1438·2021-09-28 09:44
閱讀 2501·2021-09-28 09:36
閱讀 1144·2021-09-08 09:35
閱讀 1982·2019-08-29 13:50
閱讀 810·2019-08-29 13:29
閱讀 1130·2019-08-29 13:15
閱讀 1724·2019-08-29 13:00
閱讀 2988·2019-08-26 16:16