vue-admin-better前端页面-菜单-权限配置

码云地址:

https://gitee.com/chu1204505056/vue-admin-better

其登录逻辑为:

1、登录拿取到token,分配到vuex中;

2、通过token拿取到用户的permission角色名称,用户头像,昵称,并存放到vuex中;

3、每次路由时候,调取配置的permission.js ,如果没有角色名称,则返回第二步,如果有,则通

过token向后台请求当前用户的权限路由,并对基础路由进行拼接,存放到vuex中进行状态管理;

1、登录部分

调用 this.$store .dispatch('user/login', this.form)并返回值,

user/login这样调用是因为,store中导出namespaced为true,就可以根据简写找到vuex中actions的方法

export default {

    namespaced: true,//引用需要的模块名称 /menu/GetUserMenu

    state,

    mutations,

    actions

}

login() {
      this.loading = true
      this.$store
        .dispatch('user/login', this.form)
        .then(() => {
          const routerPath = '/'
          this.$router.push(routerPath).catch(() => {})
          this.loading = false
        })
        .catch(() => {
          this.loading = false
        })
    },

 import { getUserInfo, login, logout } from '@/api/userRegistration'

调用自己定义的登录接口,主要返回token

 async login({ commit }, userInfo) {
    const { data } = await login(userInfo)
    const accessToken = data.access_token;
    const setUserInfo=data.userInfo
    if (accessToken) {
      commit('setAccessToken', accessToken)
      commit('setUserInfo',setUserInfo)
      const hour = new Date().getHours()
      console.log(hour)
      const thisTime =
        hour < 8
          ? '早上好'
          : hour <= 11
          ? '上午好'
          : hour <= 13
          ? '中午好'
          : hour < 18
          ? '下午好'
          : '晚上好'
      Vue.prototype.$baseNotify(`欢迎登录${title}`, `${thisTime}!`)
    } else {
      Vue.prototype.$baseMessage(
        `登录接口异常,未正确返回${tokenName}...`,
        'error'
      )
    }
  },

登录接口

我后台采用 Spring Scurity的oauth2进行登录,接口如下

// 数据格式
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' }
// 请求头添加 Authorization: Basic client_id:client_secret
const auth = {
  username: 'mxg-blog-admin',
  password: '123456',
}

export function login(data) {
  return request({
    headers: headers,
    auth: auth,
    url: `/supplierAuth/login`,
    method: 'POST',
    params: data,
  })
}

返回字段如下 

 

2、permission.js 进行路由拦截

采用如下,对每次路由进行拦截

router.beforeResolve(async (to, from, next) => {

逻辑还是比较好理解

1、判断是否有token,判断路由是否在白名单

2、判断是否有权限角色(user/permissions)存储 

3、如果没有则获取用户权限,获取路由并拼接,如果存在,则直接访问

router.beforeResolve(async (to, from, next) => {
  if (progressBar) VabProgress.start()
  let hasToken = store.getters['user/accessToken']


  if (hasToken) {
    if (to.path === '/login') {
      next({ path: '/' })
      if (progressBar) VabProgress.done()
    } else {
      const hasPermissions =
        store.getters['user/permissions'] &&
        store.getters['user/permissions'].length > 0
      if (hasPermissions) {
        next()
      } else {
        try {
          let permissions
          if (!loginInterception) {
            //settings.js loginInterception为false时,创建虚拟权限
            await store.dispatch('user/setPermissions', ['admin'])
            permissions = ['admin']
          } else {
            permissions = await store.dispatch('user/getUserInfo')
          }

          let accessRoutes = []
          if (authentication === 'intelligence') {
            accessRoutes = await store.dispatch('routes/setRoutes', permissions)
          } else if (authentication === 'all') {
            // console.log("all")
            console.log('拿取到用户信息')
            accessRoutes = await store.dispatch('routes/setAllRoutes')
          }
          console.log(accessRoutes)
          accessRoutes.forEach((item) => {
            console.log(item)
            router.addRoute(item)
          })
          next({ ...to, replace: true })
        } catch {
          await store.dispatch('user/resetAccessToken')
          if (progressBar) VabProgress.done()
        }
      }
    }
  } else {
    console.log(routesWhiteList)
    if (routesWhiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      if (recordRoute) {
        next(`/login?redirect=${to.path}`)
      } else {
        next('/login')
      }

      if (progressBar) VabProgress.done()
    }
  }
  document.title = getPageTitle(to.meta.title)
})
router.afterEach(() => {
  if (progressBar) VabProgress.done()
})

获取用户信息 

  permissions = await store.dispatch('user/getUserInfo')

 获取用户信息

  async getUserInfo({ commit, state }) {
    const { data } = await getUserInfo(state.accessToken)
    if (!data) {
      Vue.prototype.$baseMessage('验证失败,请重新登录...', 'error')
      return false
    }
    let { permissions, username, avatar } = data
    if (permissions && username && Array.isArray(permissions)) {
      commit('setPermissions', permissions)
      commit('setUsername', username)
      commit('setAvatar', avatar)
      return permissions
    } else {
      Vue.prototype.$baseMessage('用户信息接口异常', 'error')
      return false
    }
  },

接口如下 ,这个后台可以根据token,自由发挥

export function getUserInfo(accessToken) {
  return request({
    url: '/supplierSystem/menu/userPermission',
    method: 'post',
    data: {
     "accessToken": accessToken,
    },
  })
}

获取在permission.js中路由,并动态添加到route中

       accessRoutes = await store.dispatch('routes/setAllRoutes')
          console.log(accessRoutes)
          accessRoutes.forEach((item) => {
            console.log(item)
            router.addRoute(item)
          })

在store中找到routes/setAllRoutes方法,获取后台当前用户路由,这个路由,后台要按照前端方式拼接

这个是源代码的设置路由

async setAllRoutes({ commit }) {
    let { data } = await getRouterList()
    data.push({ path: '*', redirect: '/404', hidden: true })
    let accessRoutes = convertRouter(data)
    console.log(accessRoutes);
    commit('setAllRoutes', accessRoutes)

    return accessRoutes
  },

 这个是我的设置的路由。主要是加入了按钮的权限集合在里面

  async setAllRoutes({ commit }) {
    let { data } = await getRouterList()
    let dataRoute = data.menuTreeList
    dataRoute.push({ path: '*', redirect: '/404', hidden: true })
    let accessRoutes = convertRouter(dataRoute)
    commit('setAllRoutes', accessRoutes)
    commit('setButtonList', data.buttonList)
    return accessRoutes
  },

const state = () => ({
  routes: [],
  partialRoutes: [],
  buttonList: [],
})
const getters = {
  routes: (state) => state.routes,
  partialRoutes: (state) => state.partialRoutes,
  buttonList: (state) => state.buttonList,
}
const mutations = {
  setRoutes(state, routes) {
    state.routes = constantRoutes.concat(routes)
  },
  setAllRoutes(state, routes) {
    state.routes = constantRoutes.concat(routes)
  },
  setButtonList(state, buttonList) {
    state.buttonList = buttonList
  },
  setPartialRoutes(state, routes) {
    state.partialRoutes = constantRoutes.concat(routes)
  },
}

后端构建的菜单结构模式如下 

  {
    path: '/',
    component: 'Layout',
    redirect: 'index',
    children: [
      {
        path: 'index',
        name: 'Index',
        component: '@/views/index/index',
        meta: {
          title: '首页',
          icon: 'home',
          affix: true,
        },
      },
    ],
  },
  {
    path: '/personnelManagement',
    component: 'Layout',
    redirect: 'noRedirect',
    name: 'PersonnelManagement',
    meta: { title: '人员', icon: 'users-cog', permissions: ['admin'] },
    children: [
      {
        path: 'userManagement',
        name: 'UserManagement',
        component: '@/views/personnelManagement/userManagement/index',
        meta: { title: '用户管理' },
      },
      {
        path: 'roleManagement',
        name: 'RoleManagement',
        component: '@/views/personnelManagement/roleManagement/index',
        meta: { title: '角色管理' },
      },
      {
        path: 'menuManagement',
        name: 'MenuManagement',
        component: '@/views/personnelManagement/menuManagement/index',
        meta: { title: '菜单管理', badge: 'New' },
      },
    ],
  },

后端测试构建菜单 (没有加按钮权限集合)

    @Override
    public Result selectMenuThreeByUserIdTwo(String userId) {
        ArrayList<Object> arrayList = new ArrayList<>();
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("path", "/");
        hashMap.put("component", "Layout");
        hashMap.put("redirect", "index");
        LinkedList<Object> children = new LinkedList<>();
        HashMap<String, Object> hashMap1 = new HashMap<>();
        hashMap1.put("path", "index");
        hashMap1.put("name", "Index");
        hashMap1.put("component", "@/views/index/index");
        HashMap<Object, Object> hashMap2 = new HashMap<>();
        hashMap2.put("title", "首页");
        hashMap1.put("meta", hashMap2);
        children.add(hashMap1);

        hashMap.put("children", children);
        arrayList.add(hashMap);


        HashMap<String, Object> hashMap11 = new HashMap<>();
        hashMap11.put("path", "/personnelManagement");
        hashMap11.put("component", "Layout");
        hashMap11.put("redirect", "noRedirect");

        hashMap11.put("name", "PersonnelManagement");

        HashMap<Object, Object> hashMap22 = new HashMap<>();
        hashMap22.put("title", "人员管理");
        hashMap11.put("meta", hashMap22);
        ArrayList<Object> arrayList2 = new ArrayList<>();
        HashMap<Object, Object> hashMap3 = new HashMap<>();
        hashMap3.put("path", "userManagement");
        hashMap3.put("name", "UserManagement");
        hashMap3.put("component", "@/views/personnelManagement/userManagement/index");

        HashMap<Object, Object> hashMap4 = new HashMap<>();
        hashMap4.put("title", "人员管理");

        hashMap3.put("meta", hashMap4);
        arrayList2.add(hashMap3);
        HashMap<Object, Object> hashMap5 = new HashMap<>();
        hashMap5.put("path", "roleManagement");
        hashMap5.put("name", "roleManagement");
        hashMap5.put("component", "@/views/personnelManagement/roleManagement/index");

        HashMap<Object, Object> hashMap6 = new HashMap<>();
        hashMap6.put("title", "角色管理");

        hashMap5.put("meta", hashMap6);
        arrayList2.add(hashMap5);

        HashMap<Object, Object> hashMap7 = new HashMap<>();
        hashMap7.put("path", "roleManagement");
        hashMap7.put("name", "roleManagement");
        hashMap7.put("component", "@/views/personnelManagement/roleManagement/index");

        HashMap<Object, Object> hashMap8 = new HashMap<>();
        hashMap8.put("title", "菜单管理");
//        hashMap8.put("badge","New");
        hashMap7.put("meta", hashMap6);
        arrayList2.add(hashMap7);
        hashMap11.put("children", arrayList2);
        arrayList.add(hashMap11);
        return Result.ok(arrayList);
    }

右边页面

通过如下导入的 vab-side-bar文件,如果你想自定义修改菜单栏,则可以找到下面修改

在nodemudle中可以查看下载的菜单文件, 

3、自定义按钮权限 

前面在菜单和按钮集合存在vuex之后;配置自定义指令,来显示或者隐藏按钮

// 引入所有要注册的全局指令
import permission from './permission'
// 将permission文件导出的对象引入
export default (Vue) => {
  // 第一个参数为指令名称,v-permission 使用,
  // 注意在生命指令名时候,不能加v-
  Vue.directive('permission', permission)
}
// 然后在main.js 中全局引入这个文件

permission .js如下

//自定义权限指令
import store from '@/store/index'
// 导出一个对象
export default {
  // 指令钩子
  inserted(el, binding) {
    //el 指令作用到哪个元素上
    //获取使用指令时传递的值
    const { value } = binding
    //获取用户当前所拥有的按钮权限
    //  store.getters['user/permissions']
    // const buttonList = store.getters && store.getters.buttonList
    const buttonList = store.getters['routes/buttonList']

    if (value) {
      // 用some,不用foreach 因为如果下面为true,则进行终止循环
      const hasPermission = buttonList.some((button) => {
        return button === value
      })
      // 如果没有权限,则将元素移除
      if (!hasPermission) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    } else {
      throw new Error("需要权限标识!比如v-permission='article:delete'")
    }
  },
}

 在main.js中引入这个自定义指令,

import directive from '@/directive' //导入自定义指令

Vue.use(directive)

使用如下 

 <el-button
                type="primary"
                @click="handleQuery"
                v-permission="'user:search'"
              >
                搜索
              </el-button>

 

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue-admin-better 是一个基于 Vue.js 和 Element UI 的后台管理系统解决方案,它提供了丰富的组件和功能,使开发者可以轻松地构建出美观、易用的后台管理系统。以下是 Vue-admin-better 的开发文档: 1. 安装和使用 Vue-admin-better 可以通过 npm 安装,安装命令如下: ``` npm install vue-admin-better --save ``` 安装完成后,可以在项目中引入 Vue-admin-better: ```javascript import Vue from 'vue' import VueAdminBetter from 'vue-admin-better' Vue.use(VueAdminBetter) ``` 引入后即可在项目中使用 Vue-admin-better 的组件和功能。 2. 组件和功能 Vue-admin-better 提供了丰富的组件和功能,以下是一些常用的组件和功能: - 表格组件:提供了丰富的表格功能,如分页、排序、筛选等。 - 表单组件:提供了各种表单元素,如输入框、下拉框、日期选择器等。 - 对话框组件:提供了对话框功能,如确认框、提示框等。 - 菜单组件:提供了菜单功能,可以根据权限动态生成菜单。 - 权限控制功能:可以根据用户权限控制页面和功能的访问。 - 主题定制功能:可以根据需求定制主题,包括颜色、字体等。 3. 示例代码 以下是一个简单的 Vue-admin-better 示例代码: ```vue <template> <div> <va-table :columns="columns" :data="data" /> </div> </template> <script> export default { data() { return { columns: [ { title: '姓名', dataIndex: 'name' }, { title: '年龄', dataIndex: 'age' }, { title: '地址', dataIndex: 'address' } ], data: [ { name: '张三', age: 18, address: '北京市' }, { name: '李四', age: 20, address: '上海市' }, { name: '王五', age: 22, address: '广州市' } ] } } } </script> ``` 以上代码展示了如何在 Vue-admin-better 中使用表格组件,其中 columns 定义了表格的列,data 定义了表格的数据。 4. 总结 Vue-admin-better 是一个强大的后台管理系统解决方案,它提供了丰富的组件和功能,可以帮助开发者快速构建出美观、易用的后台管理系统。以上是 Vue-admin-better 的简要开发文档,希望对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值