Vue プロジェクトの実際の人材プラットフォーム システム (12) 権限管理モジュール (以下)

序文

1. ページ アクセスとメニューに権限を適用する

1.1 権限制御の実装アイデア

これまで、ユーザーに役割を割り当て、役割にパーミッションを割り当てましたが、ユーザーが情報を取得するためにログインしたときに、そのユーザーがどのパーミッションを持っているかを自動的に調べ、ユーザーのアクセス ルーティングとメニュー表示をユーザーのパーミッションに応じて制御する必要があります。パーミッション。

権限管理ページでは、ルーティング モジュールに関連付けることができる識別子を設定します。つまり、ユーザーがこの識別子を持っている場合、ユーザーはルーティング モジュールにアクセスでき、識別子がない場合、ユーザーはそれにアクセスできません。 . ルーティング モジュール。

最終的な権限制御プロセスを次の図に示します。
ここに画像の説明を挿入

1.2 Vuex で新しい管理権限モジュールを作成する

src/store/modules/permission.js に次のコードを追加します。

// vuex的权限模块
import {
    
     constantRoutes } from '@/router'

// vuex中的permission模块用来存放当前的 静态路由 + 当前用户的 权限路由
const state = {
    
    
  routes: constantRoutes // 所有人默认拥有静态路由
}

const mutations = {
    
    
  // newRoutes可以认为是 用户登录 通过权限所得到的动态路由的部分
  setRoutes(state, newRoutes) {
    
    
    // 每次更新在静态路由的基础上进行追加
    state.routes = [...constantRoutes, ...newRoutes]
  }
}

const actions = {
    
    }

export default {
    
    
  namespaced: true,
  state,
  mutations,
  actions
}

src/stroe/index.js に permisson モジュールを導入します。

import permission from './modules/permission'
    
const store = new Vuex.Store({
    
    
  modules: {
    
    
    app,
    settings,
    user,
    permission
  },
  getters
})

1.3 Vuex でフィルタリング権限のルーティング方法を定義する

src/store/modules/permission.js でアクション メソッドを定義します。

import {
    
     asyncRoutes, constantRoutes } from '@/router'

const actions = {
    
    
  // 筛选权限路由
  // 第二个参数为当前用户的所拥有的菜单权限
  // menus: ["settings","permissions"]
  // asyncRoutes是所有的动态路由
  // asyncRoutes  [{path: 'setting',name: 'setting'},{}]
  filterRoutes(context, menus) {
    
    
    const routes = []
    //   筛选出 动态路由中和menus中能够对上的路由
    menus.forEach(key => {
    
    
      // key就是标识
      // asyncRoutes 找 有没有对象中的name属性等于 key的 如果找不到就没权限 如果找到了 要筛选出来
      routes.push(...asyncRoutes.filter(item => item.name === key)) // 得到一个数组 有可能 有元素 也有可能是空数组
    })
    // 得到的routes是所有模块中满足权限要求的路由数组
    // routes就是当前用户所拥有的 动态路由的权限
    context.commit('setRoutes', routes) // 将动态路由提交给mutations
    return routes // 这里为什么还要return  state数据 是用来 显示左侧菜单用的  return  是给路由addRoutes用的
  }

1.4 アクセス許可傍受時に審査許可アクションを呼び出す

src/permission.js に次のコードを追加します。

// 权限拦截在路由跳转  导航守卫
import router from '@/router'
import store from '@/store' // 引入store实例 和组件中的this.$store是一回事
import nprogress from 'nprogress' // 引入进度条
import 'nprogress/nprogress.css' // 引入进度条样式

// 不需要导出  因为只需要让代码执行即可
// 前置守卫
// next是前置守卫必须必须必须执行的钩子  next必须执行 如果不执行 页面就死了
// next()  放过  next(false) 跳转终止 next(地址) 跳转到某个地址
const whiteList = ['/login', '/404'] // 定义白名单
router.beforeEach(async(to, from, next) => {
    
    
  nprogress.start() // 开启进度条
  if (store.getters.token) {
    
    
    // 只有有token的情况下 才能获取资料
    if (to.path === '/login') {
    
    
      // 如果要访问的是登录页,就跳到主页
      next('/') 
    } else {
    
    
      // 如果当前vuex中有用户的资料的id 表示 已经有资料了 不需要获取了 如果没有id才需要获取
      if (!store.getters.userId) {
    
    
        // 如果没有id才表示当前用户资料没有获取过
        const {
    
     roles } = await store.dispatch('user/getUserInfo')
        // 筛选用户的可用路由
        const routes = await store.dispatch('permission/filterRoutes', roles.menus)
        // routes就是筛选得到的动态路由
        // 添加动态路由到路由表  铺路
        router.addRoutes(routes) 
        // 添加完动态路由之后
        next(to.path) // 相当于跳到对应的地址  相当于多做一次跳转 为什么要多做一次跳转
        // 进门了,但是进门之后我要去的地方的路还没有铺好,直接走,掉坑里,多做一次跳转,再从门外往里进一次,跳转之前 把路铺好,再次进来的时候,路就铺好了
      } else {
    
    
        next()
      }
    }
  } else {
    
    
    //   没有token的情况下
    if (whiteList.indexOf(to.path) > -1) {
    
    
      //  表示要去的地址在白名单
      next()
    } else {
    
    
      next('/login')
    }
  }
  nprogress.done() // 解决手动切换地址时 进度条不关闭的问题
})
// 后置守卫
router.afterEach(() => {
    
    
  nprogress.done() // 关闭进度条
})

1.5 静的ルーティングと動的ルーティングのマージ解除

src/router/index.js 内の次のコードを変更します。

const createRouter = () => new Router({
    
    
  scrollBehavior: () => ({
    
     y: 0 }),
  routes: [...constantRoutes] // 改成只有静态路由
})

1.6 左側のメニューを変更してルーティング方法を読む

まず、src/store/getters.js でエクスポート ルートを構成します。

const getters = {
    
    
  routes: state => state.permission.routes // 导出当前的路由
}
export default getters

次に、src\layout\components\Sidebar\index.vue の動的ルーティングを変更して読み取ります。

  computed: {
    
    
    ...mapGetters([
      'sidebar', 'routes'
    ]),

2.ログアウト時にルーティング権限をリセットする

router/index.js では、プロジェクトにリセット ルーティング メソッドが含まれていることがわかりました。

// 重置路由
export function resetRouter() {
    
    
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // 重新设置路由的可匹配路径
}

したがって、ログアウトするときにこのメソッドを呼び出すだけで済みます
.src\store\modules\user.js 内の次のコードを変更します。

  // 登出操作
  logout(context) {
    
    
    // 删除token
    context.commit('removeToken')
    // 删除用户资料
    context.commit('removeUseInfo')
    // 重置路由
    resetRouter() // 重置路由
    // 去设置权限模块下路由为初始状态
    // Vuex子模块怎么调用子模块的action 都没加锁的情况下 可以随意调用
    // 不加命名空间的情况下的 所有的mutations和action都是挂在全局上的 所以可以直接调用
    // 但是加了命名空间的子模块 怎么调用另一个加了命名空间的子模块的mutations
    // 加了命名空间的context指的不是全局的context
    // mutations名称 载荷 payload 第三个参数  { root: true } 调用根级的mutations或者action
    context.commit('permission/setRoutes', [], {
    
     root: true })
  }

また、ページを更新するとパーミッションが必要なページが 404 になっていることがわかりました.
これは動的ルートの最後に 404 を入れていなかったためです.
src/permission.js に以下のコードを追加してください.

router.addRoutes([...routes, {
    
     path: '*', redirect: '/404', hidden: true }]) // 添加到路由表

3. Mixin テクノロジーを使用して機能権限の適用を実現する

新しい技術 mixin (mixing in) を使用して、すべてのコンポーネントに共通のメソッドを持たせることができます.
次のコードを src/mixin/checkPermission.js に追加します:

import store from '@/store'
// 做一个混入对象
export default {
    
    
  // 混入对象是组件的选项对象
  methods: {
    
    
    // 检查权限 要么有 没有没有 key就是要检查的点
    checkPermission(key) {
    
    
      // 去用户的信息里面找 points中有没有key 如果有key 则认为有权限 如果没有key则认为不能点击
      //  store.state.user.userInfo.roles.points
      const {
    
     userInfo } = store.state.user
      if (userInfo.roles && userInfo.roles.points) {
    
    
        return userInfo.roles.points.some(item => item === key)
      }
      return false // 如果没进去 说明没权限
    }
  }
}

従業員コンポーネントの許可ポイントを確認してください

<el-button :disabled="!checkPermission('POINT-USER-UPDATE')" type="text" size="small" @click="$router.push(`/employees/detail/${obj.row.id}`)">查看</el-button>

要約する

おすすめ

転載: blog.csdn.net/qq_40652101/article/details/127219838