herozhou / vue-framework-wz

👏vue后台管理框架👏
http://herozhou.coding.me/vue-framework-wz/#/dashboard
MIT License
4.33k stars 1.34k forks source link

如何先屏蔽权限校验动态生成路由的功能 #7

Closed wuzechuan closed 7 years ago

wuzechuan commented 7 years ago

你好,我这边功能是想先实现基础功能,还没有涉及权限的部分,如何屏蔽权限校验的部分,账号一登陆就可以直接展示所有东西呢?

herozhou commented 7 years ago

那就不再路由里设置权限信息

 {path: '/table', name: '表格综合实例',icon:'ios-paper',component: _import('Table'),meta: { role: ['admin'] }},

其中的

meta: { role: ['admin'] }

就是配置的权限信息,只要不加这个就不会牵涉到权限问题

wuzechuan commented 7 years ago

我后端登陆接口里没有返回roles的字段,返回的字典是result,我设了一个个人信息的字段info,还有一个专门存token的字段 在login.js文件处理beforeeach的方法里面

store.dispatch('GetInfo').then(res => { // 拉取user_info
          const roles = res.data.role

          store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成可访问的路由表
            router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表
            next({ ...to }) // hack方法 确保addRoutes已完成
          })
        }).catch(() => {
          store.dispatch('FedLogOut').then(() => {
            next({ path: '/login' })

const roles = res.data.role 这里应该是const roles = res.result.info的是吧 如果赋值给store.dispatch('GenerateRoutes', { roles }).then(() 这里权限校验的话,会报 Unhandled promise rejection TypeError: Cannot read property 'indexOf' of undefined(…) 也就是permission文件里的(roles.indexOf('admin' ,校验这个)

GenerateRoutes({ commit }, data) {
      return new Promise(resolve => {
        const { roles } = data
        let accessedRouters
        if (roles.indexOf('admin') >= 0) {
          accessedRouters = asyncRouterMap
        } else {
          accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
        }

        commit('SET_ROUTERS', accessedRouters);
        resolve();

这里面需要有个admin的值,如果只屏蔽meta['admin']的话,应该还是不够的吧? 我的页面现在是登录了,但是还是在登录页面,因为出现了那个错误

herozhou commented 7 years ago

如果你已经移除了mock.js,请求外部api的话,还需要修改src/store/modules/user.js。

image 如果得不到response, Promise reject了,就登录失败了

herozhou commented 7 years ago

image 这样是最简便的,不请求后端,直接设置cookies为admin

wuzechuan commented 7 years ago

那么这样一来就不是存的后端给的token了吧,可以先屏蔽那段if (roles.indexOf('admin') 这个判断不?

herozhou commented 7 years ago

token的作用是要判断是否登录,看你的意思是你需要登录但是不需要权限。 不需要权限的话也可以直接修改 src/login.js 如果登录,直接next下个路由,如果没有,就跳到登录

// register global progress.
const whiteList = ['/login', '/authredirect']// 不重定向白名单
router.beforeEach((to, from, next) => {
  NProgress.start() // 开启Progress
  if (store.getters.token) { // 判断是否有token
    if (to.path === '/login') {
      next({ path: '/' })
    } else {
       next();
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
      next()
    } else {
      next('/login') // 否则全部重定向到登录页
      NProgress.done() // 在hash模式下 改变手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
    }
  }
})
wuzechuan commented 7 years ago

@herozhou 但是登陆进来后,侧边栏asyncRouterMap 的好像没有加载出来,是把url都放到constantRouterMap这里?

herozhou commented 7 years ago

不好意思把侧边栏给忘了

const whiteList = ['/login', '/authredirect']// 不重定向白名单
router.beforeEach((to, from, next) => {
  NProgress.start() // 开启Progress
  if (store.getters.token) { // 判断是否有token
    if (to.path === '/login') {
      next({ path: '/' })
    } else {

     // 这个要加上。生成侧边栏
          store.dispatch('getNowRoutes', to);

       next();
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
      next()
    } else {
      next('/login') // 否则全部重定向到登录页
      NProgress.done() // 在hash模式下 改变手动改变hash 重定向回来 不会触发afterEach 暂时hack方案 ps:history模式下无问题,可删除该行!
    }
  }
})

还有侧边栏是从src/store/modules/permission.js里获取的,这里也需要改

image

路由的话就把asyncRouterMap的路由对象放到constantRouterMap里

wuzechuan commented 7 years ago

@herozhou 我按照你的修改后,页面还是没加载侧边栏,然后有个报错的提示:

es6.promise.js?903b:103 Unhandled promise rejection TypeError: Cannot read property 'forEach' of undefined
    at SET_NOW_ROUTERS (eval at <anonymous> (http://localhost:9528/app.js:1843:1), <anonymous>:79:23)
    at wrappedMutationHandler (eval at <anonymous> (http://localhost:9528/app.js:1108:1), <anonymous>:596:5)
    at commitIterator (eval at <anonymous> (http://localhost:9528/app.js:1108:1), <anonymous>:320:7)
    at Array.forEach (native)
    at eval (eval at <anonymous> (http://localhost:9528/app.js:1108:1), <anonymous>:319:11)
    at Store._withCommit (eval at <anonymous> (http://localhost:9528/app.js:1108:1), <anonymous>:407:3)
    at Store.commit (eval at <anonymous> (http://localhost:9528/app.js:1108:1), <anonymous>:318:8)
    at boundCommit (eval at <anonymous> (http://localhost:9528/app.js:1108:1), <anonymous>:274:19)
    at eval (eval at <anonymous> (http://localhost:9528/app.js:1843:1), <anonymous>:110:9)
    at new Promise (eval at <anonymous> (http://localhost:9528/app.js:2080:1), <anonymous>:177:7)
herozhou commented 7 years ago

我不知道你是怎么写的,我这边是没问题,我先把代码都贴出啦你比对一下,重点是路由的代码,一定要有children,不能写空的父元素。 src/router/index.js

import Vue from 'vue';
import Router from 'vue-router';
const _import = require('./_import_' + process.env.NODE_ENV);
import Full from '@/containers/Full'
import Full2 from '@/containers/Full2'

import Buttons from '@/views/components/Buttons'

// Views - Pages
import Page404 from '@/views/errorPages/Page404'
import Page500 from '@/views/errorPages/Page500'

/* login */
const Login = _import('login/index');
Vue.use(Router);

export const constantRouterMap = [
    { path: '/login', component: Login, hidden: true },
    {path: '/pages',redirect: '/pages/p404', name: 'Pages',
          component: {
            render (c) { return c('router-view') }
              // Full,
          },
          children: [{path: '404',  name: 'Page404', component: _import('errorPages/Page404') },
                     {path: '500',name: 'Page500',component: _import('errorPages/Page404')},
                    ]
    },
     {
    path: '/',
    redirect: '/dashboard',
    name: '首页',
    component: Full,
    hidden:false,
    children: [
     {path: '/dashboard',name: 'Dashboard',icon:'speedometer',component: _import('Dashboard')},
     {path: '/introduction',name: '介绍',icon:'thumbsup',component: _import('Introduction')},
     {path: '/components',name: 'component组件',redirect: '/components/buttons',icon:'bookmark',
        component: {render (c) { return c('router-view') }},
        children: [ {path: 'buttons',name: 'Buttons按钮',icon:'social-youtube',component: _import('components/Buttons'), hidden:false, },
                    {path: 'hoverbuttons',name: '悬停特效按钮',icon:'wand',component: _import('components/HoverButtons')},
                    {path: 'alert',name: 'Alert警告提示',icon:'alert',component: _import('components/Alert')},
                    {path: 'card',name: 'Card卡片',icon:'ios-browsers-outline',component: _import('components/Card')},
                    {path: 'datepicker',name: 'DatePicker',icon:'ios-calendar-outline',component: _import('components/DatePicker')},
                    {path: 'form',name: 'Form表单',icon:'ios-list-outline',component: _import('components/Form')},
                    {path: 'modal',name: 'Modal对话框',icon:'ios-chatbubble-outline',component: _import('components/Modal')},
                    {path: 'select',name: 'Select选择器',icon:'ios-arrow-down',component: _import('components/Select')},
                    {path: 'spin',name: 'Spin加载中',icon:'load-d ',component: _import('components/Spin')},
                    {path: 'steps',name: 'Steps步骤条',icon:'ios-checkmark-outline',component: _import('components/Steps')},
                    {path: 'timeline',name: 'Timeline时间轴',icon:'android-more-vertical',component: _import('components/Timeline')},
                    {path: 'transfer',name: 'Transfer穿梭框',icon:'ios-pause-outline',component: _import('components/Transfer')},
                    {path: 'timepicker',name: 'Timepicker',icon:'ios-clock-outline',component: _import('components/Timepicker')},
                    {path: 'upload',name: 'Upload上传',icon:'ios-cloud-upload-outline',component: _import('components/Upload')},
                  ]
      },
       {path: '/charts',name: 'echart图表',redirect: '/charts/shopchart',icon:'pie-graph',
        component: {render (c) { return c('router-view') }},
        children: [ {path: 'shopchart',name: '商场统计图表',icon:'stats-bars',component: _import('charts/ShopChart'), hidden:false, },
                    {path: 'radarchart',name: '雷达图',icon:'arrow-graph-up-right',component: _import('charts/RadarChart')},
                    {path: 'cakechart',name: '蛋糕销量图表',icon:'ios-analytics',component: _import('charts/CakeChart')}
                  ]
      },
      {path: '/table', name: '表格综合实例',icon:'ios-paper',component: _import('Table'),meta: { role: ['admin'] }},
      {path: '/jsontree', name: 'JSON视图',icon:'merge',component: _import('JsonTree')},
      {path: '/tabledetail/:id',name: 'TableDetail', hidden:true, component: _import('TableDetail')},
      {path: '/tinymce',name: 'Tinymce编辑器',icon:"android-document",component: _import('Tinymce')},
      {path: '/markdown',name: 'Markdown',icon:"android-list",component: _import('Markdown')},

    ]
  },

   {
    path: '/home1',
    redirect: '/home1/introduction',
    name: 'home',
    component: Full2,
    hidden:false,
    children: [
     {path: '/home1/dashboard',name: 'Dashboard2',icon:'speedometer',component: _import('Dashboard2')},
     {path: '/home1/introduction',name: '介绍2',icon:'thumbsup',component: _import('Introduction')},

    ]
  },

  { path: '*', redirect: '/pages/404', hidden: true }

]

export default new Router({
  mode: 'hash', 
  linkActiveClass: 'open active',
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRouterMap
});

export const asyncRouterMap = [

];
herozhou commented 7 years ago

src/srore/modules/permission.js

import { asyncRouterMap, constantRouterMap } from 'src/router';

/**
 * 通过meta.role判断是否与当前用户权限匹配
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
  if (route.meta && route.meta.role) {
    return roles.some(role => route.meta.role.indexOf(role) >= 0)
  } else {
    return true
  }
}

/**
 * 递归过滤异步路由表,返回符合用户角色权限的路由表
 * @param asyncRouterMap
 * @param roles
 */
function filterAsyncRouter(asyncRouterMap, roles) {
  const accessedRouters = asyncRouterMap.filter(route => {
    if (hasPermission(roles, route)) {

      if (route.children && route.children.length) {
        route.children = filterAsyncRouter(route.children, roles)
      }
      return true
    }
    return false
  })
  return accessedRouters
}

function getNowRouter(asyncRouterMap, to) {
  return asyncRouterMap.some(route => {
      if(route.path===to.path) {
          return true;
      }
      else if (route.children && route.children.length) { //如果有孩子就遍历孩子
        return  getNowRouter(route.children, to)
      }
  })

}

const permission = {
  state: {
    routers: constantRouterMap,
    addRouters: constantRouterMap,
    siderbar_routers:constantRouterMap,
  },
  mutations: {
    SET_ROUTERS: (state, routers) => {
      state.addRouters = routers;
      state.routers = constantRouterMap.concat(routers);
      // state.routers.forEach(function(e){
      //     if(e.name==="首页"){
      //     state.siderbar_routers=e;

      //     }

      // })

    },
     SET_NOW_ROUTERS: (state, to) => {

//你是在这里报错的,要不是路由没有配置正确,要不就是这个函数的问题

          // 递归访问 accessedRouters,找到包含to 的那个路由对象,设置给siderbar_routers
          console.log(state.addRouters)
        state.addRouters.forEach(e => {
          if(e.children&& e.children.length ){
           if( getNowRouter(e.children,to)===true)
                  state.siderbar_routers=e;
          }

        })

     }

  },
  actions: {
    GenerateRoutes({ commit }, data) {
      return new Promise(resolve => {
        const { roles } = data
        let accessedRouters
        if (roles.indexOf('admin') >= 0) {
          accessedRouters = asyncRouterMap
        } else {
          accessedRouters = filterAsyncRouter(asyncRouterMap, roles)
        }

        commit('SET_ROUTERS', accessedRouters);
        resolve();
      })
    },

  getNowRoutes({ commit }, data) {
      return new Promise(resolve => {
        //data => to
        commit('SET_NOW_ROUTERS', data);
        resolve();
      })
  },
   },
};

export default permission;
herozhou commented 7 years ago

如果还是有问题把你邮箱发给我,我把代码发给你

herozhou commented 7 years ago

你先试下这样行不行

export const constantRouterMap = [
  { path: '/login', component: Login, hidden: true },
  { path: '/404', component: Err404, hidden: true },
  {
    path: '/release',
    component: Layout,
    redirect: 'noredirect',
    name: '发布管理',
    icon: 'zonghe',
    children: [
      { path: '/release/index', component: _import('release/releaselist'), name: '发布列表' },
      { path: '/release/flowlist', component: _import('release/flowlist'), name: '审批流列表' }
    ]
  },
  { path: '*', redirect: '/404', hidden: true },
  //{ path: '/approvetable/rid/:id', component: _import('release/singlerelease'), hidden: true }, 
  {
    path: '/',
    component: Layout,
    redirect: '/introduction',
    name: 'Home',
    hidden: true,
    children: [{ path: '/introduction', component: introduction }]
  }
]
wuzechuan commented 7 years ago

@herozhou 还是报那个错误

herozhou commented 7 years ago

方便把你代码发到我邮箱吗?

wuzechuan commented 7 years ago

@herozhou ok,发到你邮箱了