国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Vue 動態路由的實現及 Springsecurity 按鈕級別的權限控制

2019-11-19 10:53:01
字體:
來源:轉載
供稿:網友

思路 :

動態路由實現:在導航守衛中判斷用戶是否有用戶信息, 通過調用接口,拿到后臺根據用戶角色生成的菜單樹, 格式化菜單樹結構信息并遞歸生成層級路由表并 使用Vuex保存,通過  router.addRoutes  動態掛載到  router  上,按鈕級別的權限控制,則需使用自定義指令去實現。

實現:

導航守衛代碼:

router.beforeEach((to, from, next) => { NProgress.start() // start progress bar to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`)) if (getStore('ACCESS_TOKEN')) { /* has token */ if (to.path === '/user/login') {  next({ path: '/other/list/user-list' })  NProgress.done() } else {  if (store.getters.roles.length === 0) {  store   .dispatch('GetInfo')   .then(res => {   const username = res.principal.username   store.dispatch('GenerateRoutes', { username }).then(() => {    // 根據roles生成可訪問的路由表    // 動態添加可訪問路由表    router.addRoutes(store.getters.addRouters)    const redirect = decodeURIComponent(from.query.redirect || to.path)    if (to.path === redirect) {    // hack方法 確保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record    next({ ...to, replace: true })    } else {    // 跳轉到目的路由    next({ path: redirect })    }   })   })   .catch(() => {   notification.error({    message: '錯誤',    description: '請求用戶信息失敗,請重試'   })   store.dispatch('Logout').then(() => {    next({ path: '/user/login', query: { redirect: to.fullPath } })   })   })  } else {  next()  } } } else { if (whiteList.includes(to.name)) {  // 在免登錄白名單,直接進入  next() } else {  next({ path: '/user/login', query: { redirect: to.fullPath } })  NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it } }})

Vuex保存routers

const permission = { state: { routers: constantRouterMap, addRouters: [] }, mutations: { SET_ROUTERS: (state, routers) => {  state.addRouters = routers  state.routers = constantRouterMap.concat(routers) } }, actions: { GenerateRoutes ({ commit }, data) {  return new Promise(resolve => {  generatorDynamicRouter(data).then(routers => {   commit('SET_ROUTERS', routers)   resolve()  })  }) } }}

路由工具,訪問后端接口獲得菜單樹,然后對菜單樹進行處理,把菜單樹的組件字符串進行轉換為前端的組件如:

userlist: () => import('@/views/other/UserList'),這樣生成的路由就是我們所要的了。

import { axios } from '@/utils/request'import { UserLayout, BasicLayout, RouteView, BlankLayout, PageView } from '@/layouts'// 前端路由表const constantRouterComponents = { // 基礎頁面 layout 必須引入 BasicLayout: BasicLayout, BlankLayout: BlankLayout, RouteView: RouteView, PageView: PageView, // 需要動態引入的頁面組件 analysis: () => import('@/views/dashboard/Analysis'), workplace: () => import('@/views/dashboard/Workplace'), monitor: () => import('@/views/dashboard/Monitor'), userlist: () => import('@/views/other/UserList') // ...more}// 前端未找到頁面路由(固定不用改)const notFoundRouter = { path: '*', redirect: '/404', hidden: true}/** * 獲取后端路由信息的 axios API * @returns {Promise} */export const getRouterByUser = (parameter) => { return axios({ url: '/menu/' + parameter.username, method: 'get' })}/** * 獲取路由菜單信息 * * 1. 調用 getRouterByUser() 訪問后端接口獲得路由結構數組 * 2. 調用 * @returns {Promise<any>} */export const generatorDynamicRouter = (data) => { return new Promise((resolve, reject) => { // ajax getRouterByUser(data).then(res => {  // const result = res.result  const routers = generator(res)  routers.push(notFoundRouter)  resolve(routers) }).catch(err => {  reject(err) }) })}/** * 格式化 后端 結構信息并遞歸生成層級路由表 * * @param routerMap * @param parent * @returns {*} */export const generator = (routerMap, parent) => { return routerMap.map(item => { const currentRouter = {  // 路由地址 動態拼接生成如 /dashboard/workplace  path: `${item && item.path || ''}`,  // 路由名稱,建議唯一  name: item.name || item.key || '',  // 該路由對應頁面的 組件  component: constantRouterComponents[item.component || item.key],  // meta: 頁面標題, 菜單圖標, 頁面權限(供指令權限用,可去掉)  meta: { title: item.name, icon: item.icon || undefined, permission: item.key && [ item.key ] || null } } // 為了防止出現后端返回結果不規范,處理有可能出現拼接出兩個 反斜杠 currentRouter.path = currentRouter.path.replace('//', '/') // 重定向 item.redirect && (currentRouter.redirect = item.redirect) // 是否有子菜單,并遞歸處理 if (item.children && item.children.length > 0) {  // Recursion  currentRouter.children = generator(item.children, currentRouter) } return currentRouter })}

后端菜單樹生成工具類

/** * 構造菜單樹工具類 * @author dang * */public class TreeUtil { protected TreeUtil() { } private final static Long TOP_NODE_ID = (long) 1; /**  * 構造前端路由  * @param routes  * @return  */ public static ArrayList<MenuEntity> buildVueRouter(List<MenuEntity> routes) {  if (routes == null) {   return null;  }  List<MenuEntity> topRoutes = new ArrayList<>();  routes.forEach(route -> {   Long parentId = route.getParentId();   if (TOP_NODE_ID.equals(parentId)) {    topRoutes.add(route);    return;   }   for (MenuEntity parent : routes) {    Long id = parent.getId();    if (id != null && id.equals(parentId)) {     if (parent.getChildren() == null) {      parent.initChildren();     }     parent.getChildren().add(route);     return;    }   }  });  ArrayList<MenuEntity> list = new ArrayList<>();  MenuEntity root = new MenuEntity();  root.setName("首頁");  root.setComponent("BasicLayout");  root.setPath("/");  root.setRedirect("/other/list/user-list");  root.setChildren(topRoutes);  list.add(root);  return list; }}

菜單實體 (使用了lombok插件)

/** * 菜單實體 * @author dang * */public class MenuEntity extends CoreEntity { private static final long serialVersionUID = 1L; @TableField("FParentId") private Long parentId; @TableField("FNumber") private String number; @TableField("FName") private String name; @TableField("FPerms") private String perms; @TableField("FType") private int type; @TableField("FLongNumber") private String longNumber; @TableField("FPath") private String path; @TableField("FComponent") private String component; @TableField("FRedirect") private String redirect; @TableField(exist = false) private List<MenuEntity> children; @TableField(exist = false) private MenuMeta meta; @TableField(exist = false) private List<PermissionEntity> permissionList; @Override public int hashCode() {  return number.hashCode(); } @Override public boolean equals(Object obj) {  return super.equals(obj(obj); } public void initChildren() {  this.children = new ArrayList<>(); }}

路由菜單是根據用戶的角色去獲得的,一個用戶具有多個角色,一個角色具有多個菜單

思路:

說下按鈕權限控制的實現:前端vue主要用自定義指令實現控制按鈕的顯示與隱藏,后端我用的是SpringSecurity框架,所以使用的是 @PreAuthorize注解, 在菜單實體的 perms屬性記錄權限的標識,如:sys:user:add,記錄有權限標識的菜單其 parentId 應為上級菜單,然后獲取用戶的perms集合,在用戶登錄的時候傳給前端并用Vuex保存,在自定義指令中去比較用戶是否含有按鈕所需要的權限。

實現:

獲取用戶信息的時候,把權限存到Vuex中   commit('SET_PERMISSIONS', result.authorities)

 // 獲取用戶信息 GetInfo ({ commit }) {  return new Promise((resolve, reject) => {  getInfo().then(response => {   const result = response   if (result.authorities) {   commit('SET_PERMISSIONS', result.authorities)   commit('SET_ROLES', result.principal.roles)   commit('SET_INFO', result)   } else {   reject(new Error('getInfo: roles must be a non-null array !'))   }   commit('SET_NAME', { name: result.principal.displayName, welcome: welcome() })   commit('SET_AVATAR', result.principal.avatar)   resolve(response)  }).catch(error => {   reject(error)  })  }) }

前端自定義指令

// 定義一些和權限有關的 Vue指令// 必須包含列出的所有權限,元素才顯示export const hasPermission = { install (Vue) { Vue.directive('hasPermission', {  bind (el, binding, vnode) {  const permissions = vnode.context.$store.state.user.permissions  const per = []  for (const v of permissions) {   per.push(v.authority)  }  const value = binding.value  let flag = true  for (const v of value) {   if (!per.includes(v)) {   flag = false   }  }  if (!flag) {   if (!el.parentNode) {   el.style.display = 'none'   } else {   el.parentNode.removeChild(el)   }  }  } }) }}// 當不包含列出的權限時,渲染該元素export const hasNoPermission = { install (Vue) { Vue.directive('hasNoPermission', {  bind (el, binding, vnode) {  const permissions = vnode.context.$store.state.user.permissions  const per = []  for (const v of permissions) {   per.push(v.authority)  }  const value = binding.value  let flag = true  for (const v of value) {   if (per.includes(v)) {   flag = false   }  }  if (!flag) {   if (!el.parentNode) {   el.style.display = 'none'   } else {   el.parentNode.removeChild(el)   }  }  } }) }}// 只要包含列出的任意一個權限,元素就會顯示export const hasAnyPermission = { install (Vue) { Vue.directive('hasAnyPermission', {  bind (el, binding, vnode) {  const permissions = vnode.context.$store.state.user.permissions  const per = []  for (const v of permissions) {   per.push(v.authority)  }  const value = binding.value  let flag = false  for (const v of value) {   if (per.includes(v)) {   flag = true   }  }  if (!flag) {   if (!el.parentNode) {   el.style.display = 'none'   } else {   el.parentNode.removeChild(el)   }  }  } }) }}// 必須包含列出的所有角色,元素才顯示export const hasRole = { install (Vue) { Vue.directive('hasRole', {  bind (el, binding, vnode) {  const permissions = vnode.context.$store.state.user.roles  const per = []  for (const v of permissions) {   per.push(v.authority)  }  const value = binding.value  let flag = true  for (const v of value) {   if (!per.includes(v)) {   flag = false   }  }  if (!flag) {   if (!el.parentNode) {   el.style.display = 'none'   } else {   el.parentNode.removeChild(el)   }  }  } }) }}// 只要包含列出的任意一個角色,元素就會顯示export const hasAnyRole = { install (Vue) { Vue.directive('hasAnyRole', {  bind (el, binding, vnode) {  const permissions = vnode.context.$store.state.user.roles  const per = []  for (const v of permissions) {   per.push(v.authority)  }  const value = binding.value  let flag = false  for (const v of value) {   if (per.includes(v)) {   flag = true   }  }  if (!flag) {   if (!el.parentNode) {   el.style.display = 'none'   } else {   el.parentNode.removeChild(el)   }  }  } }) }}

在main.js中引入自定義指令

import Vue from 'vue'import { hasPermission, hasNoPermission, hasAnyPermission, hasRole, hasAnyRole } from './utils/permissionDirect'Vue.use(hasPermission)Vue.use(hasNoPermission)Vue.use(hasAnyPermission)Vue.use(hasRole)Vue.use(hasAnyRole)

這樣就可以在按鈕中使用自定義指令,沒有權限時,按鈕自動隱藏,使用Postman工具測試也會拒絕訪問

 <a-button type="primary" @click="handleAddUser()" v-hasPermission="['sys:user:add']" icon="plus"

總結

以上所述是小編給大家介紹的Vue 動態路由的實現以及 Vue 動態路由的實現及 Springsecurity 按鈕級別的權限控制Springsecurity 按鈕級別的權限控制,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 淳安县| 龙井市| 安仁县| 新兴县| 乐都县| 雷州市| 阿荣旗| 苍溪县| 扎鲁特旗| 马关县| 濉溪县| 泸定县| 麟游县| 莎车县| 永宁县| 施秉县| 城口县| 苏州市| 安阳市| 年辖:市辖区| 横山县| 木兰县| 筠连县| 逊克县| 天峨县| 油尖旺区| 临湘市| 开阳县| 奇台县| 唐海县| 江山市| 靖安县| 昌乐县| 庆云县| 清远市| 红安县| 南靖县| 靖州| 四平市| 宝鸡市| 达拉特旗|