vue-element-admin用户权限管理,根据不同用户获取动态路由,刷新页面需重新登录bug处理

问题的主要原因是用户角色登录的时候就获取到了,起初没有另外的接口再去获取用户信息。其实在登录的时候,不能给角色赋值,否则执行有token无roles这一步,就获取不到动态路由。
后来新增一个接口通过用户id再去获取用户角色,但跟原框架通过token获取用户角色不同,就又冒出每次刷新页面却跳到登录页面去了的问题,这个通过localStorage来处理。

这里通过一个流程图展示src/promission.jsrouter.beforeEach的运行逻辑(必须要2这条线才能获取到动态路由):
在这里插入图片描述

根据用户权限动态加载路由涉及文件有 src/promission.js ,router.beforeEach内容使用模板本身的就行。

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") {
      // if is logged in, redirect to the home page
      next({ path: "/" });
      NProgress.done();
    } else {
      const hasRoles = store.getters.roles && store.getters.roles.length > 0;
      if (hasRoles) {
        next();
      } else {
        try {
          // get user info
          // note: roles must be a object array! such as: ['admin'] or ,['developer','editor']
          const { roles } = await store.dispatch("user/getInfo");
          // generate accessible routes map based on roles
          const accessRoutes = await store.dispatch(
            "permission/generateRoutes",
            roles
          );
          // dynamically add accessible routes
          router.addRoutes(accessRoutes);
          // 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 });
        } 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();
    }
  }
});

我在这里的问题主要是在登录的时候就获取角色,其实这里不能给角色赋值,否则就不能进入第2二条线,获取不到动态路由。

文件 store/modules/user.js
action中 的 login() ,获取 tokenid,这里使用 localStorage 是为了解决通过id获取roles导致的 刷新页面却跳到登录页面并有错误警告 的问题。

login({ commit }, userInfo) {
    const { username, password } = userInfo;
    return new Promise((resolve, reject) => {
      login({
        username: username.trim(),
        password: password
      })
        .then(response => {
          const { data } = response;
          commit("SET_TOKEN", data.token);
          commit("SET_USERID", data.user.id);
          // 储存id,刷新页面时调用
          localStorage.setItem("userId", JSON.stringify(data.user.id));
          setToken(data.token);
          resolve();
        })
        .catch(error => {
          reject(error);
        });
    });
  }

action中 的 getInfo() , 获取 roles,这里JSON.parse(localStorage.getItem(“userId”)) 释放储存在localStorage中的id,并传给getInfo接口(我这里的接口接收的参数是id而不是token),否则刷新页面的时候会执行router.beforeEach的第2条线时id不存在,导致需要重新登录还报错,因为token是储存在cookie当中的,而后设的id并没有储存在cookie中,所以刷新页面的时候只有token没有id,getInfo这个就执行不成功。localStorage就是解决这个问题的。

getInfo({ commit, state }) {
    const id = JSON.parse(localStorage.getItem("userId"));
    commit("SET_USERID", id);
    return new Promise((resolve, reject) => {
      getInfo(state.id)
        .then(response => {
          // debugger;
          const { data } = response;
          if (!data) {
            reject("Verification failed, please Login again.");
          }
          const { roles } = data;
          if (!roles || roles.length <= 0) {
            reject("getInfo: roles must be a non-null array!");
          }
          commit("SET_ROLES", roles);
          resolve(data);
        })
        .catch(error => {
          reject(error);
        });
    });
  },

下面补充2点
要将src/router/index.js里面的路由分为 2 部分,constantRoutes是不需要权限都能访问的路由比如登录,404等页面,asyncRoutes放需要权限控制的路由,并在路由的 mate中添加 roles属性,roles放有访问权限的角色

import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);

/**
 * constantRoutes
 * a base page that does not have permission requirements
 * all roles can be accessed
 */
export const constantRoutes = [
  {
    path: "/login",
    component: () => import("@/views/login/index"),
    hidden: true
  },
  {
    path: "/404",
    component: () => import("@/views/404"),
    hidden: true
  }
];
/**
 * asyncRoutes
 * the routes that need to be dynamically loaded based on user roles
 */
export const asyncRoutes = [
  {
    path: "/",
    component: () => import("@/views/dashboard/index"),
    redirect: "/dashboard",
    children: [
      {
        path: "dashboard",
        name: "Dashboard",
        hidden: true,
        meta: { title: "主页", affix: true }
      }
    ]
  },
  {
    path: "/dashboard/firm",
    name: "firm",
    component: firm,
    hidden: true,
    meta: { roles: ["admin", "user"] }
  },
  {
    path: "/dashboard/map",
    name: "map",
    component: map,
    hidden: true,
    meta: { roles: ["admin"] }
  },

  // 404 page must be placed at the end !!!
  { path: "*", redirect: "/", hidden: true }
];
const createRouter = () =>
  new Router({
    // mode: "history", // require service support
    scrollBehavior: () => ({ y: 0 }),
    routes: constantRoutes
  });

const router = createRouter();

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
export function resetRouter() {
  const newRouter = createRouter();
  router.matcher = newRouter.matcher; // reset router
}

export default router;

src/layout/components/Sidebar/index中循环的routes需要换成permission_routes,permission_routes在src/store/getter中定义

<sidebar-item v-for="route in permission_routes"
                      :key="route.path"
                      :item="route"
                      :base-path="route.path" />
computed: {
    ...mapGetters(["permission_routes", "sidebar"]),
Logo

前往低代码交流专区

更多推荐