前端权限管理

权限:一个系统,要设计不同的用户角色,超级管理员,普通管理员、... 具有的权限不一样(看见的不一样,能操作的权限不一样)。

举个栗子: 设计一个医院的管理系统,有哪些角色: 护士 医生 主任医生 院长 ..., 这些用户,登录的,看到的东西一样么?(不一样),具有的操作权限一样吗?(不一样)

注意:

  • 权限可以由后端计算,前端只要发送ajax,拿到数据,渲染就好了。

  • 也可以由端计算, 整个权限的计算过程,在前端实现。

1.1 登录成功,后端返回用户角色

登录成功,后端返回了用户角色,我们要把当前用户的角色,存入本地。之后,我们需要使用这个角色,把权限计算出来。

 local.set("role", role); // 存用户角色 (登录成功的接口里面 存入本地)

1.2 角色权限划分

  • 超级管理员: super

    • 所有

  • 普通管理员: normal

    • 后台首页

    • 订单管理

    • 商品管理

      • 商品列表

      • 商品分类

    • 账号管理

      • 修改密码

      • 个人中心

1.3 配置路由

把权限变成可以配置的通用的方案。

1.3.1 路由一分为三

  • 静态路由(默认都可以访问的)

/* *********** 静态路由 *********** */
const routes = [
  // 登录
  {
    path: '/login',
    component: Login
  },
  // 后台首页
  {
    path: '/',
    component: Layout,
    redirect: '/home',
    meta: { path: "/home", title: "后台首页" },
    children: [
      {
        path: '/home',
        component: () => import('@/views/home/Home.vue')
      }
    ]
  },
]
  • 动态路由(哪个角色,能够访问什么路由,需要计算出来)

    在meta中配置权限: 规则是:如果不配置,默认都可以看见, 如果配置了的:就是roles的数组中有这个角色,这个角色就可以访问。

/* ********* 动态路由 ********* */
const dynamicRoutes = [
  // 账号管理
  {
    path: '/account',
    component: Layout,
    redirect: '/account/account-list',
    meta: { path: "/account", title: "账号管理" },
    children: [
      {
        path: '/account/account-list',
        component: () => import('@/views/account/AccountList.vue'),
        meta: { path: "/account/account-list", title: "账号列表", roles: ['super'] },
      },
      {
        path: '/account/account-add',
        component: () => import('@/views/account/AccountAdd.vue'),
        meta: { path: "/account/account-add", title: "账号添加", roles: ['super'] },
      },
      {
        path: '/account/password-modify',
        component: () => import('@/views/account/PasswordModify.vue'),
        meta: { path: "/account/password-modify", title: "修改密码" },
      },
      {
        path: '/account/personal',
        component: () => import('@/views/account/Personal.vue'),
        meta: { path: "/account/personal", title: "个人中心" },
      }
    ]
  },
  // 商品管理
  {
    path: '/goods',
    component: Layout,
    redirect: '/goods/goods-list',
    meta: { path: "/goods", title: "商品管理" },
    children: [
      {
        path: '/goods/goods-list',
        component: () => import('@/views/goods/GoodsList.vue'),
        meta: { path: "/goods/goods-list", title: "商品列表" },
      },
      {
        path: '/goods/goods-add',
        component: () => import('@/views/goods/GoodsAdd.vue'),
        meta: { path: "/goods/goods-add", title: "商品添加", roles: ['super'] },
      },
      {
        path: '/goods/goods-cate',
        component: () => import('@/views/goods/GoodsCate.vue'),
        meta: { path: "/goods/goods-cate", title: "商品分类" },
      },
    ]
  },
  // 订单管理
  {
    path: '/order',
    component: Layout,
    meta: { path: "/order", title: "订单管理" },
    children: [
      {
        path: '',
        component: () => import('@/views/order/Order.vue')
      },
    ]
  },
  // 店铺管理
  {
    path: '/shop',
    component: Layout,
    meta: { path: "/shop", title: "店铺管理", roles: ['super'] },
    children: [
      {
        path: '',
        component: () => import('@/views/shop/Shop.vue')
      },
    ]
  },
  // 销售统计
  {
    path: '/total',
    component: Layout,
    redirect: '/total/goods-total',
    meta: { path: "/total", title: "销售统计", roles: ['super'] },
    children: [
      {
        path: '/total/goods-total',
        component: () => import('@/views/total/GoodsTotal.vue'),
        meta: { path: "/total/goods-total", title: "商品统计" },
      },
      {
        path: '/total/order-total',
        component: () => import('@/views/total/OrderTotal.vue'),
        meta: { path: "/total/order-total", title: "订单统计" },
      },
    ]
  },
]
  • 重定向404路由
/* ********* 重定向404 *********  */
const errorRoutes = [
  // 重定向404
  {
    path: '*',
    redirect: '/error404'
  },
  {
    path: '/error404',
    component: () => import('@/views/error/Error404.vue')
  }
]

1.4 写3个函数,计算有权限访问的路由

1.4.1 写在 router/indexjs中

/* 判断是否有权限 */


const hasPermissioin = (router, role) => {
  if (router.meta && router.meta.roles) {
    return router.meta.roles.includes(role)
  } else {
    return true; // 没有配置roles(默认就是可以访问)
  }
}

​/* 计算出哪些路由是可以访问的 */
/* 计算出哪些路由是可以访问的 */
const calcPermisstionRoutes = (dynamicRoutes, role) => {
  // 把有权限的动态路由 计算出来
  let temp = dynamicRoutes.filter(v => {
    // 如果有权限 就返回true 把这个单个路由对象 放入temp
    if (hasPermissioin(v, role)) {
​
      if (v.children && v.children.length) {
​
        // 递归算儿子的权限
        v.children = calcPermisstionRoutes(v.children, role)
​
      }
​
      return true;
    } else {
      // 否则 就是没有权限 就返回false 不放入temp
      return false;
    }
  })
​
  return temp
}
/* 计算出有权限访问的路由 并且 动态添加路由 让算出来的路由可以访问 */

/* 计算出有权限访问的路由 并且 动态添加路由 让算出来的路由可以访问 */
export const createRoutes = () => {
  let role = local.get('role') // 取出本地当前用户角色
​
  // 如果没有角色 直接return 不走后面。
  if (!role) return;
​
  // 调用一个函数,把能够访问的路由计算出来 传入:两个参数: 所有动态路由 和 当前角色
  let accessRoutes = calcPermisstionRoutes(dynamicRoutes, role)
​
  // 把算出来的路由 重新动态的添加到路由实例中 然后这些路由 就可以访问了。
  router.addRoutes([...routes, ...accessRoutes, ...errorRoutes])
}

1.4.2 调用两次

  • 登录成功,就要调用(在角色存入之后:计算过程需要根据角色来,在跳转之前: 跳转到home之前,就算好了,到home之后,直接看到的就是计算结果了)

// 调用的地方: 存入了角色之后 跳转之前
createRoutes();
  • 路由中也要调用一次(防止刷新)

createRoutes();

1.5 计算菜单

/* 计算菜单 */
const calcMenus = (routes) => {
  return routes.filter(v => v.isMenu)
}

1.6 解决切换账号bug

只要去登录就刷新一次

# RightHeader.vue
// 刷新(所有代码重置 路由也会清空 重新来 解决切换不同角色账号登录的bug)
window.location.reload();
​
# router/index.js
 // 刷新 解决切换角色的bug
  if (from.path !== '/' && to.path === '/login') {
    window.location.reload()
  }

1.7 动态渲染菜单

  • 算出菜单,存入本地  

    // 根据权限路由计算左侧菜单
      let menus = calcMenus([...routes, ...accessRoutes])
    ​
      // 存入本地
      local.set('menus', menus)

  • 在左侧导航组件,取出菜单数据,动态渲染

<template>
  <div class="left-menu">
    <!-- logo -->
    <div class="logo-container">
      <img width="50" height="50" src="../../assets/imgs/logo.png" alt="logo" />
      <span>外卖商家中心</span>
    </div>
​
    <!-- 导航 -->
    <el-menu
      background-color="#304156"
      text-color="#eee"
      :default-active="$route.path"
      unique-opened
      router
    >
      <template v-for="menu in menus">
        <!-- 没有儿子的 -->
        <el-menu-item
          v-if="menu.children && menu.children.length === 1"
          :index="menu.meta.path"
          :key="menu.path"
        >
          <i class="iconfont icon-home"></i>
          <span slot="title">{{ menu.meta.title }}</span>
        </el-menu-item>
​
        <!-- 有儿子的 -->
        <el-submenu v-else :index="menu.path" :key="menu.path">
          <template slot="title">
            <i class="iconfont icon-goods"></i>
            <span>{{ menu.meta.title }}</span>
          </template>
          <el-menu-item
            v-for="v in menu.children"
            :key="v.path"
            :index="v.meta.path"
            >{{ v.meta.title }}</el-menu-item
          >
        </el-submenu>
      </template>
    </el-menu>
  </div>
</template>
​
<script>
import local from "@/utils/local";
​
export default {
  data() {
    return {
      menus: [],
    };
  },
  created() {
    this.menus = local.get("menus");
    console.log(this.menus);
  },
};
</script>
​
<style lang="less" scoped>
.left-menu {
  width: 200px;
  background-color: #304156;
  .logo-container {
    height: 60px;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #eee;
  }
  .el-menu {
    border-right: 0px;
    .el-menu-item {
      .iconfont {
        margin-right: 10px;
      }
    }
    .el-submenu {
      .el-submenu__title {
        .iconfont {
          margin-right: 10px;
        }
      }
      .el-menu-item {
        background-color: #202f3f !important;
​
        &:hover {
          color: #fff !important;
          background-color: rgba(0, 0, 0, 0.5) !important;
        }
      }
    }
  }
}
</style>

 

  • 8
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值