前言

在编辑vue-element-template之前,后台需要实现login等接口。

@RestController
@RequestMapping("/admin")
@CrossOrigin    //解决跨域
public class LoginController {

    //login
    @PostMapping("login")
    public R login(){
        return R.ok().data("token","admin");
    }

    //info
    @GetMapping("info")
    public R info(){
        List<String> roles = new ArrayList<>();
        roles.add("test");
        return R.ok().data("roles",roles).data("name","admin").data("avatar","https://scpic.chinaz.net/files/pic/pic9/201708/zzpic5968.jpg");
    }

    @PostMapping("logout")
    public R logout(){
        return R.ok();
    }
}

注:roles要返回数据形式

一、安装vue-element-template基础模板?

下载安装链接:

vue-element-template快速入门

注:这里使用的是基础模板: vue-admin-template。

二、具体步骤

1.修改路由文件

注意文件夹位置:src/router/index.js
添加asyncRoutes

代码如下(示例):
注意:要将 { path: ‘*’, redirect: ‘/404’, hidden: true }放在最后

//异步挂载的路由
//动态需要根据权限加载的路由表 
export const asyncRoutes = [
  {
    path: '/example1',
    component: Layout,
    redirect: '/example/table',
    name: 'Example',
    meta: { title: 'Example', icon: 'el-icon-s-help' ,roles: ['test']},
    children: [
      {
        path: 'table',
        name: 'Table',
        component: () => import('@/views/table/index'),
        meta: { title: 'Table', icon: 'table' ,roles: ['test']}
      },
      {
        path: 'tree',
        name: 'Tree',
        component: () => import('@/views/tree/index'),
        meta: { title: 'Tree', icon: 'tree' ,roles: ['test']}
      }
    ]
  },
  { path: '*', redirect: '/404', hidden: true }
];

2.挂载前的验证

注意文件夹位置:src/permission.js

这里分了核心三步,第一步获取用户个人信息(角色);第二部筛选用户可以看见的路由;第三步更新加载路由

代码如下(示例):

router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  // determine whether the user has logged in
  const hasToken = getToken()

  if (hasToken) {
    if (to.path === '/login') { // 判断是否有token
      // if is logged in, redirect to the home page
      next({ path: '/' })
      NProgress.done()
    } else {
      const hasGetUserInfo = store.getters.name 
      // const hasRoles = store.getters.roles && store.getters.roles.length > 0//这里指的是src/store/getters.js的roles
      // console.log(hasRoles)
      if (hasGetUserInfo) {// 判断当前用户是否已拉取完user_info信息
        next() 
      } else {
        try {
          // get user info
          await store.dispatch('user/getInfo') // 拉取info

          //获取roles
          const { roles } = await store.dispatch('user/getInfo')//第一步
          console.log("roles:",roles)
          
          // generate accessible routes map based on roles
          //获取通过权限验证的路由
          const accessRoutes = await store.dispatch('permission/generateRoutes', roles)//第二步

          //更新加载路由
          router.options.routes = store.getters.permission_routes//第三步
          // dynamically add accessible routes
          router.addRoutes(accessRoutes)
          // console.log(store)
          // hack method to ensure that addRoutes is complete
          // set the replace: true, so the navigation will not leave a history record
          next({ ...to, replace: true })
          // next()
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch('user/resetToken')
          Message.error(error || 'Has Error')
          next(`/login?redirect=${to.path}`)
          NProgress.done()
        }
      }
    }
  } else {
    /* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {
      // in the free login whitelist, go directly
      next()
    } else {
      // other pages that do not have permission to access are redirected to the login page.
      next(`/login?redirect=${to.path}`)
      NProgress.done()
    }
  }
})

3.获取用户角色,保存一些从后台获得的roles相关信息

注意文件夹位置:src/store/modules/user.js

注意roles和SET_ROLES是必须的

代码如下(示例):

const getDefaultState = () => {
  return {
    token: getToken(),
    name: '',
    avatar: '',
    roles: []
  }
}
const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar
  },
  SET_ROLES: (state, roles) => {
    state.roles = roles
  }
}
// get user info
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo(state.token).then(response => {
        const { data } = response

        if (!data) {
          return reject('Verification failed, please Login again.')
        }

        const { name, avatar , roles } = data

        if (!roles || roles.length <= 0) {
          reject('getInfo: roles must be a non-null array!')
        }

        commit('SET_NAME', name)
        commit('SET_AVATAR', avatar)
        commit('SET_ROLES',roles)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

修改src/store/getters.js
在这里插入图片描述

4.筛选路由

注意路径:src/store/modules/permission.js

若没有则新建
代码如下(示例):

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

/**
 * Use meta.role to determine if the current user has permission
 * @param roles
 * @param route
 */
//匹配权限
function hasPermission(roles, route) {
  if (route.meta && route.meta.roles) {
    return roles.some(role => route.meta.roles.includes(role))
  } else {
    return true
  }
}

/**
 * Filter asynchronous routing tables by recursion
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes, roles) {
  const res = []

  routes.forEach(route => {

    const tmp = { ...route }
    if (hasPermission(roles, tmp)) {
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles)
      }
      res.push(tmp)
    }
  })

  return res
}

const state = {
  routes: [],
  addRoutes: []
}

const mutations = {
  SET_ROUTES: (state, routes) => {
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes) // 将过滤后的路由和constantRoutes存起来
  }
}

//筛选
const actions = {
  generateRoutes({ commit }, roles) {
      
    return new Promise(resolve => {
      let accessedRoutes
      //路由是否有admin,有直接全部显示

      if (roles.includes('admin')) {
        accessedRoutes = asyncRoutes || []
      } else {
        //过滤路由
        accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
        //accessedRoutes这个就是当前角色可见的动态路由
      }
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  }
}

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

5.最后的加载

在第三步已经做过就是这句代码:

 router.options.routes = store.getters.permission_routes

很多人直接用router.addRoutes(accessRoutes)发现无法更新路由,但是路由是被定义了的;后面看文档,是因为Router的路由并不是响应式的,所以只能读取到初始路由。然后要在router.addRoutes(accessRoutes),加上那句话就可以了
或者参考一下大佬的加载方法
手摸手,带你用vue撸后台 系列二(登录权限篇)

6.别忘了修改登录、推出、获取用户信息路径

注意路径:src/api/user.js
里的路径改为
前言中的路径

三、遇到的bug

1.data functions should return an object:

后台roles要为数组形式,这里改为List就可以了

@GetMapping("info")
    public R info(){
        List<String> roles = new ArrayList<>();
        roles.add("test");
        return R.ok().data("roles",roles).data("name","admin").data("avatar","https://scpic.chinaz.net/files/pic/pic9/201708/zzpic5968.jpg");
    }

2.配置后台api接口baseUrl不生效

  1. 修改env.development文件
# base api
#VUE_APP_BASE_API = '/dev-api'
VUE_APP_BASE_API = 'http://127.0.0.1:8001'
  1. 修改vue.config.js

注:// before: require(’./mock/mock-server.js’),要注释掉

devServer: {
    port: port,
    open: true,
    overlay: {
      warnings: false,
      errors: true
    },
    // before: require('./mock/mock-server.js'),
    proxy: {
      [process.env.VUE_APP_BASE_API]: {
        target: process.env.VUE_APP_BASE_API,
        changeOrigin: true,  //配置跨域
        pathRewrite: {
          ['^' + process.env.VUE_APP_BASE_API]: ''
        }
      }
    }
  },

3.配置完第2部api后,报错Proxy error: Could not proxy request auth/code from 127.0.0.1:9527 to 127.0.0.1:8001

原来,在上一步修改env.development文件时,没有加http,加上后就可以了
在这里插入图片描述

4.无法识别generateRoutes方法:“[vuex] unknown action type: permission/generateRoutes”

原因:未声明导出
修改 store/index.js
加两行

import permission from './modules/permission'

permission

在这里插入图片描述

总结

本博文参考了
https://blog.csdn.net/luhjkehr/article/details/109656030

其他bug请参考
vue-admin-template动态路由实现+问题解决

Logo

前往低代码交流专区

更多推荐