欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue 動態(tài)路由的實現(xiàn)及 Springsecurity 按鈕級別的權(quán)限控制

 更新時間:2019年09月05日 08:16:43   作者:我是是是蕩啊  
這篇文章主要介紹了Vue 動態(tài)路由的實現(xiàn)以及 Springsecurity 按鈕級別的權(quán)限控制的相關(guān)知識,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下

思路 :

動態(tài)路由實現(xiàn):在導(dǎo)航守衛(wèi)中判斷用戶是否有用戶信息, 通過調(diào)用接口,拿到后臺根據(jù)用戶角色生成的菜單樹, 格式化菜單樹結(jié)構(gòu)信息并遞歸生成層級路由表并 使用Vuex保存,通過  router.addRoutes  動態(tài)掛載到  router  上,按鈕級別的權(quán)限控制,則需使用自定義指令去實現(xiàn)。

實現(xiàn):

導(dǎo)航守衛(wèi)代碼:

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(() => {
    // 根據(jù)roles生成可訪問的路由表
    // 動態(tài)添加可訪問路由表
    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 {
    // 跳轉(zhuǎn)到目的路由
    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()
  })
  })
 }
 }
}

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

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

import { axios } from '@/utils/request'
import { UserLayout, BasicLayout, RouteView, BlankLayout, PageView } from '@/layouts'
// 前端路由表
const constantRouterComponents = {
 // 基礎(chǔ)頁面 layout 必須引入
 BasicLayout: BasicLayout,
 BlankLayout: BlankLayout,
 RouteView: RouteView,
 PageView: PageView,
 // 需要動態(tài)引入的頁面組件
 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. 調(diào)用 getRouterByUser() 訪問后端接口獲得路由結(jié)構(gòu)數(shù)組
 * 2. 調(diào)用
 * @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)
 })
 })
}
/**
 * 格式化 后端 結(jié)構(gòu)信息并遞歸生成層級路由表
 *
 * @param routerMap
 * @param parent
 * @returns {*}
 */
export const generator = (routerMap, parent) => {
 return routerMap.map(item => {
 const currentRouter = {
  // 路由地址 動態(tài)拼接生成如 /dashboard/workplace
  path: `${item && item.path || ''}`,
  // 路由名稱,建議唯一
  name: item.name || item.key || '',
  // 該路由對應(yīng)頁面的 組件
  component: constantRouterComponents[item.component || item.key],
  // meta: 頁面標(biāo)題, 菜單圖標(biāo), 頁面權(quán)限(供指令權(quán)限用,可去掉)
  meta: { title: item.name, icon: item.icon || undefined, permission: item.key && [ item.key ] || null }
 }
 // 為了防止出現(xiàn)后端返回結(jié)果不規(guī)范,處理有可能出現(xiàn)拼接出兩個 反斜杠
 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
 })
}

后端菜單樹生成工具類

/**
 * 構(gòu)造菜單樹工具類
 * @author dang
 *
 */
public class TreeUtil {

 protected TreeUtil() {

 }

 private final static Long TOP_NODE_ID = (long) 1;
 /**
  * 構(gòu)造前端路由
  * @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<>();
 }
}

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

思路:

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

實現(xiàn):

獲取用戶信息的時候,把權(quán)限存到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)
  })
  })
 }

前端自定義指令

// 定義一些和權(quán)限有關(guān)的 Vue指令
// 必須包含列出的所有權(quán)限,元素才顯示
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)
   }
  }
  }
 })
 }
}
// 當(dāng)不包含列出的權(quán)限時,渲染該元素
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)
   }
  }
  }
 })
 }
}
// 只要包含列出的任意一個權(quán)限,元素就會顯示
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)

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

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

總結(jié)

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

相關(guān)文章

  • Vue3+TS實現(xiàn)數(shù)字滾動效果CountTo組件

    Vue3+TS實現(xiàn)數(shù)字滾動效果CountTo組件

    最近開發(fā)有個需求需要酷炫的文字滾動效果,發(fā)現(xiàn)vue2版本的CountTo組件不適用與Vue3,沒有輪子咋辦,那咱造一個唄,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-11-11
  • vue-admin如何實現(xiàn)動態(tài)路由

    vue-admin如何實現(xiàn)動態(tài)路由

    這篇文章主要介紹了vue-admin如何實現(xiàn)動態(tài)路由問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 詳解vue v-model

    詳解vue v-model

    這篇文章主要介紹了vue v-model的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)vue,感興趣的朋友可以了解下
    2020-08-08
  • vue項目中添加electron的詳細(xì)代碼

    vue項目中添加electron的詳細(xì)代碼

    這篇文章通過實例代碼給大家介紹了vue項目中添加electron的方法,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-11-11
  • Vue3使用postcss-px-to-viewport實現(xiàn)頁面自適應(yīng)

    Vue3使用postcss-px-to-viewport實現(xiàn)頁面自適應(yīng)

    postcss-px-to-viewport 是一個 PostCSS 插件,它可以將 px 單位轉(zhuǎn)換為視口單位,下面我們就看看如何使用postcss-px-to-viewport實現(xiàn)頁面自適應(yīng)吧
    2024-01-01
  • vue?element-ui的el-input-number默認(rèn)值設(shè)置為空方法

    vue?element-ui的el-input-number默認(rèn)值設(shè)置為空方法

    這篇文章主要給大家介紹了關(guān)于vue?element-ui的el-input-number默認(rèn)值設(shè)置為空的相關(guān)資料,el-input-number組件是Element?UI非常常用的一個數(shù)字輸入框組件,它提供了默認(rèn)值設(shè)置的選項,需要的朋友可以參考下
    2023-08-08
  • vue學(xué)習(xí)筆記之作用域插槽實例分析

    vue學(xué)習(xí)筆記之作用域插槽實例分析

    這篇文章主要介紹了vue學(xué)習(xí)筆記之作用域插槽,結(jié)合實例形式分析了vue.js作用域插槽基本使用方法及操作注意事項,需要的朋友可以參考下
    2020-02-02
  • vue中路由重定向redirect問題

    vue中路由重定向redirect問題

    這篇文章主要介紹了vue中路由重定向redirect問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • 解決v-for中使用v-if或者v-bind:class失效的問題

    解決v-for中使用v-if或者v-bind:class失效的問題

    今天小編就為大家分享一篇解決v-for中使用v-if或者v-bind:class失效的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • vue3.0 vue-router4.0打包后頁面空白的解決方法

    vue3.0 vue-router4.0打包后頁面空白的解決方法

    本文主要介紹了vue3.0 vue-router4.0打包后頁面空白的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02

最新評論