香菊网

幻雨焉缘

坚持比方法更重要 🥗
😃

通过动态路addRouter由来控制用户访问权限

香菊网 发表于: 2020-01-03 分类: js部分  前端front  H5部分  

引言

看了很多关于后台管理访问权限的代码和实现原理,有的是放在meta里的可访问的用户,有的是返回的 routerConfig 。主要还是看后端的实现程度。

然后自己做了一个 通过 addRouters 添加 routerConfig 来实现对路由的动态添加。

本次实现

  • 前端 可视化页面及按钮配置权限
  • 后端 处理 返回处理好路由数据
  • 前端当前登录用户
  • 后端根据登录用户返回对应的 routerConfig

路由守卫 和 动态添加路由

路由守卫  就是当前端页面的url每发生页面跳转时都会先触发 路由守卫 然后由 路由守卫 决定,是否跳到下个页面。

动态添加路由 添加用户可以跳转的路由页面路径。

实现效果图

github地址 https://github.com/liuguangqing/addRouter-for-limits

技术 : vue-cli3 + mockJs + ts + vue-router + vuex-class + element-ui + axios + addRouter

mockjs 本地模拟了用户权限接口返回,下载之后可以直接运行看到效果

 

用户登录页面

登录效果图

登录用户:front

vue 用户权限

登录用户:admin

vue 用户权限

router Api

addrouters

代码实现

1、components.ts 本地保存的路由地址

// components.ts 本地保存的路由地址
const routeMap: any = {
  index: () => import('../views/index.vue'),
  home: () => import('../views/home.vue'),
  about: () => import('../views/about.vue'),
  zhaoxin: () => import('../views/zhaoxin.vue'),
  change: () => import('../views/change.vue'),
  addAdverse: () => import('../views/addAdverse.vue')
};

export  { routeMap }

2、router.ts  Config  (主要部分)

// router.ts 路由 config
import Vue from "vue";
import VueRouter from "vue-router";
import ax from '@/service/axios';
import routes from './comonRouters';
import { formatRoutes } from './utils';
import { Message } from 'element-ui'

Vue.use(VueRouter);
const router = new VueRouter({
  mode: "history",
  routes
});
const NotFound = () => import('@/views/layout/404.vue');

router.beforeEach((to: any, from: any, next: any) => {
  let storeJs: any = router.app.$options.store
  const username = sessionStorage.getItem('username');
  if(!username && to.path !== '/login'){
    Message.error('请先登录当前用户');
    next({path: '/login'});

  } else if (storeJs.state.remoteRouteRefresh && to.path !== '/login') {
    ax({url: '/login', method: 'post', data: {token: storeJs.state.token}}).then((res: any) => {
      console.warn('模拟请求-成功', res)
      if (res.status === 200 && res.data.errno === 0) {
        const menuData = res.data.result;
        storeJs.commit('set_remoteRouteRefresh', false)
        storeJs.commit('set_menudata', menuData)
        localStorage.setItem('menudata', JSON.stringify(menuData));
        const routeData = formatRoutes(menuData);
        router.addRoutes([routeData].concat([
          {name:'404',path:'/404',component: NotFound},
          {path:'*',redirect: '/404'}
        ]));
        
        Message.success('恭喜登录成功。。');
        next(to.path)

      }
      else {
        storeJs.commit('set_remoteRouteRefresh', true)
        Message.error('不存在此用户 !');
        next({path: '/login'});
      }
    })
    .catch((err: any) => {
        console.log(err);
    });    
  } else {
    next();
  }
})

export default router;

3、utils.ts 更改后端返回的数据为路由所需要的数据

// utils.ts
import { routeMap } from './components';
interface asd {
  component?: any,
  path?: any,
  name?: any,
  index?: any,
  title?: any,
  children?: any
}

const formatRoutes = function (routes: any, routeData?: any) {
  routes.length && routes.forEach((route: asd) => {
    if (!routeData) {
      routeData = {
        path: route.path,
        name: route.name,
        // 组件匹配成功的话才可以访问具体的页面
        component: routeMap[route.component],
        children: [],
      };
    }
    if (route.component && routeData) {
      route.component = routeMap[route.component];
      routeData.children.push({
        path: route.path,
        name: route.name,
        component: route.component,
        meta: {
            title: route.title,
        },
      })
    }
    if (route.children && route.children.length) {
      formatRoutes(route.children, routeData);
    }
  });
  return routeData;
};

export { formatRoutes }

4、comonRouters.ts 公共路由 不需要用户权限的配置

// comonRouters.ts  公共路由配置
import login from "@/views/layout/login.vue";

const routes: any[] = [
  {
    path: "/",
    redirect: '/home/index'
  },
  {
    path: "/login",
    component: login
  }
];

export default routes

5、mock.ts 模拟接口返回数据

// 指定当前只有 front 和 admin 用户
import Mock from 'mockjs';

function loginFun(prarms: any) {
    const prarmsObj = JSON.parse(prarms.body);
    let sendObj = {
        "errno": 0,
        "errmsg": "获取权限成功",
        "result": [
            {
                "path": "/home",
                "name": "首页",
                "component": "home",
                "children": [
                    {
                        "path": "/home/index",
                        "name": "首页",
                        "component": "index",
                        "isShow": true
                    }
                ]
            }
        ]
    }
    if (prarmsObj.token == 'front') {
        sendObj.result[0].children.push(
            {
                "path": "/home/addAdverse",
                "name": "地址",
                "component": "addAdverse",
                "isShow": true
            },
            {
                "path": "/home/change",
                "name": "嫦娥",
                "component": "change",
                "isShow": true
            }
        )
    } else if (prarmsObj.token == 'admin') {
        sendObj.result[0].children.push(
            {
                "path": "/home/about",
                "name": "关于",
                "component": "about",
                "isShow": true
            },
            {
                "path": "/home/zhaoxin",
                "name": "赵信",
                "component": "zhaoxin",
                "isShow": true
            }
        )
    } else {
        sendObj.errno = 1
        sendObj.errmsg = '没有此用户'
        
    }
    return sendObj
}

Mock.mock('/api/login', 'post', loginFun); //登录

6、home.vue 路由菜单

       <el-aside width="200px">
          <el-menu
            :router="true"
            default-active="2"
            class="el-menu-vertical-demo"
            @open="handleOpen"
            @close="handleClose"
            background-color="#545c64"
            text-color="#fff"
            active-text-color="#ffd04b">
            <template v-for="(ite, ind) in menudata">
              <el-submenu index="1" v-if='ite.children && ite.children.length > 0'  :key="ind">
                <template slot="title">
                  <i class="el-icon-location"></i>
                  <span>{{ite.name}}</span>
                </template>
                <el-menu-item-group>
                  <el-menu-item :index="ite2.path" v-for="(ite2, ind2) in ite.children" :key="ind2">{{ite2.name}}</el-menu-item>
                </el-menu-item-group>
              </el-submenu>
              <el-menu-item :index="ite.path" v-else  :key="ind">
                <i class="el-icon-menu"></i>
                <span slot="title">{{{{ite.name}}}}</span>
              </el-menu-item>
            </template>
          </el-menu>
        </el-aside>

本地储存菜单的数据只是作为其他用途,看大家需要, 没有必要本地存的话也可以只存在vuex中 ,而且如果用户通过控制台修改了 menuData, 如果用户 F5 刷新了页面,直接去获取一次就行了。

本文出自 香菊网 xiangjv.top

思路借鉴 全能的阿豪:vue实现菜单权限控制

标签: js部分前端frontH5部分
Copyright © 2019 幻雨焉缘博客 | 浙ICP备19001843号-1
----------------------------------
种一棵树,最好的培养时间是十年前,其次是现在 加油  (ง •_•)ง。        ──── 前端攻城狮