Vue+Element UI 权限管理(角色 )

用户前台登录后,后台返回一个token,将该token存储到store中,并设置到header中,每次发起请求时都会携带该token,用于后台进行权限校验

// 登录方法 login.vue
 handleLogin() {
      this.$refs.loginForm.validate((valid) => {
        if (valid) {
          this.loading = true;
          this.$store
            .dispatch("user/login", this.loginForm)
            .then(() => {
              this.$router.push({ path: this.redirect || "/" });
              this.loading = false;
            })
            .catch(() => {
              this.loading = false;
            });
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },

在store 的user.js中定义了该方法

 login({ commit }, userInfo) {
    const { userName, userPassword } = userInfo;
    return new Promise((resolve, reject) => {
      login({ userName: userName.trim(), userPassword: userPassword })
        .then((response) => {
          const { data } = response;
          commit("SET_TOKEN", data.token);
          setToken(data.token);
          resolve();
        })
        .catch((error) => {
          reject(error);
        });
    });
  },

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_AUTHORITIES: (state, authorities) => {
    state.authorities = authorities;
  },
};

此时登录成功后,后台将返回一个token

在请求拦截器中将token添加到请求头上,在响应拦截器中设置未登录状态访问时跳转到登录页面

import axios from "axios";
import { MessageBox, Message } from "element-ui";
import store from "@/store";
import { getToken, removeToken } from "@/utils/auth";
import router from "@/router";

// create an axios instance
const service = axios.create({
  baseURL: "http://localhost:8080", // url = base url + request url
  timeout: 5000, // request timeout
});

// request interceptor
service.interceptors.request.use(
  (config) => {
    if (store.getters.token) {
      config.headers["token"] = getToken();
    }
    return config;
  },
  (error) => {
    console.log(error);
    return Promise.reject(error);
  }
);

//  response 拦截器
service.interceptors.response.use(
  (response) => {
    const res = response.data;

    // if the custom code is not 20000, it is judged as an error.
    if (res.code !== 200 && res.code !== 201) {
      Message({
        message: res.message || "Error",
        type: "error",
        duration: 5 * 1000,
      });

      // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
      if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
        // to re-login
        MessageBox.confirm(
          "You have been logged out, you can cancel to stay on this page, or log in again",
          "Confirm logout",
          {
            confirmButtonText: "Re-Login",
            cancelButtonText: "Cancel",
            type: "warning",
          }
        ).then(() => {
          store.dispatch("user/resetToken").then(() => {
            location.reload();
          });
        });
      }
      if (res.code == 401) {
        removeToken();
        router.replace({
          path: "/login",
        });
      }
      return Promise.reject(new Error(res.message || "Error"));
    } else {
      return res;
    }
  },
  (error) => {
    console.log("err" + error); // for debug
    Message({
      message: error.message,
      type: "error",
      duration: 5 * 1000,
    });
    return Promise.reject(error);
  }
);

export default service;

 在permission.js 中进行相关代码编写 (获取用户的信息,动态路由的生成加载)

 router.beforeEach()路由拦截()

import router from "./router";
import store from "./store";
import { Message } from "element-ui";
import NProgress from "nprogress"; // progress bar
import "nprogress/nprogress.css"; // progress bar style
import { getToken } from "@/utils/auth"; // get token from cookie
import getPageTitle from "@/utils/get-page-title";

NProgress.configure({ showSpinner: false }); // NProgress Configuration

const whiteList = ["/login"]; // no redirect whitelist

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();
  const hasRoles =
    store.state.user.authorities && store.state.user.authorities.length > 0;
  // 如果有token再跳转到登录页面时,根据获取的角色信息进行页面跳转
  if (hasToken) {
    if (to.path === "/login") {
      if (store.state.user.authorities) {
        if (store.state.user.authorities.includes("ROLE_ADMIN")) {
          next({ path: "/" });
        } else {
          next({ path: "/user" });
        }
      } else {
        next({ path: "/" });
      }
      NProgress.done();
    } else {
      // 获取登录用户名 如果用户名存在说明用户已经登录且获得了用户信息,直接放行,如果没有用户名,就进行用户信息获取
      const hasGetUserInfo = store.getters.name;
      if (hasGetUserInfo) {
        next();
      } else {
        try {
          //判断用户角色是否存在
          if (!hasRoles) {
            let userInfo = await store.dispatch("user/getInfo"); // 获取用户信息
            // 根据获得到的用户信息,获取用户角色信息并动态生成路由
            let routes = await store.dispatch(
              "permission/getAsyncRoutes",
              userInfo.user.authorities
            );
            router.options.routes = routes;
            router.addRoutes(routes); // 将生成的动态路由添加到原先的路由中
            next({ ...to, replace: true }); // 保证路由已挂载

            // 根据用户角色进行登录后的首页面跳转
            if (store.state.user.authorities) {
              if (store.state.user.authorities.includes("ROLE_ADMIN")) {
                next({ path: "/" });
              } else {
                next({ path: "/user/user" });
              }
            }
          }
        } catch (error) {
          // remove token and go to login page to re-login
          await store.dispatch("user/resetToken");
          Message.error(error || "Has Error");
          next(`/login`);
          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`);
      NProgress.done();
    }
  }
});

router.afterEach(() => {
  // finish progress bar
  NProgress.done();
});

获取用信息的方法定义在store的user.js中

  // 获取用户信息
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      getInfo()
        .then((response) => {
          const { data } = response;
          if (!data) {
            return reject("Verification failed, please Login again.");
          }
          const { username, authorities } = data.user;
          // 将用户名,和用户角色信息存储到store中
          commit("SET_NAME", username); 
          commit("SET_AUTHORITIES", authorities);
          resolve(data);
        })
        .catch((error) => {
          reject(error);
        });
    });
  },

在store 的 permission.js 为动态路由的相关方法和存储 

import { asyncRoutes, constantRoutes } from "@/router";
/**
 * 通过meta中的roles信息判断用户是否有权限
 * @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;
  }
}

/**
 * 根据角色和配置生成当前用户的路由
 * @param {array} routes 配置的路由
 * @param {array} roles 用户角色
 */
let GenerateRoutes = (routes, roles) => {
  let res = [];
  routes.forEach((route) => {
    const tmp = { ...route };

    if (hasPermission(roles, tmp)) {
      if (tmp.children) {
        tmp.children = GenerateRoutes(tmp.children, roles);
      }
      // console.log(tmp);
      res.push(tmp);
    }
  });

  return res;
};

const getDefaultState = () => {
  return {
    roles: [],
    routes: constantRoutes, // 用于配置页面导航等
  };
};
const state = getDefaultState();
const mutations = {
  SET_ROLES: (state, roles) => {
    state.roles = roles;
  },
  SET_ROUTES: (state, routes) => {
    state.routes = routes;
  },
};

const actions = {
  /**根据角色获取路由配置 */
  getAsyncRoutes({ commit }, roles) {
    let filterRoutes = GenerateRoutes(asyncRoutes, roles);
    let res = constantRoutes.concat(filterRoutes);
    commit("SET_ROUTES", res);
    return res;
  },
};

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

将新增的js文件引入store的index.js文件中

import Vue from "vue";
import Vuex from "vuex";
import getters from "./getters";
import app from "./modules/app";
import settings from "./modules/settings";
import user from "./modules/user";
import permission from "./modules/permission"; 

Vue.use(Vuex);

const store = new Vuex.Store({
  modules: {
    app,
    settings,
    user,
    permission, 
  },
  getters,
});

export default store;

路由文件

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

Vue.use(Router);

/* Layout */
import Layout from "@/layout";

// 默认路由
export const constantRoutes = [
  {
    path: "/login",
    component: () => import("@/views/login/index"),
    hidden: true,
  },
  {
    path: "/404",
    component: () => import("@/views/404"),
    hidden: true,
  },
];
// 自定义动态路由,在meta中添加了roles,通过roles中是角色进行动态生成不同角色的动态路由
export const asyncRoutes = [
  {
    path: "/",
    component: Layout,
    redirect: "/employee",
    meta: { roles: ["ROLE_ADMIN"] },
    children: [
      {
        path: "employee",
        name: "Employee",
        component: () => import("@/views/employee/index"),
        // meta: { title: "员工管理", icon: "el-icon-s-custom" },
        meta: {
          roles: ["ROLE_ADMIN"],
          title: "员工管理",
          icon: "el-icon-s-custom",
        },
      },
    ],
  },
 {
    path: "/user",
    component: Layout,
    meta: { roles: ["ROLE_DEPT", "ROLE_EMP"] },
    children: [
      {
        path: "user",
        name: "User",
        component: () => import("@/views/user/index"),
        meta: {
          roles: ["ROLE_DEPT", "ROLE_EMP"],
          title: "个人信息",
          icon: "el-icon-setting",
        },
      },
    ],
  },
// 404 page must be placed at the end !!!
  { path: "*", redirect: "/404", 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;

 此时登录成功并获取到用户信息后,可在控制台看到存储到store中的信息

 登录成功界面实例

管理员

部门经理

基本员工

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值