当前位置:   article > 正文

Vue权限管理的实现流程_vue权限管理怎么实现

vue权限管理怎么实现
  1. 权限管理是什么

权限管理是指一个角色(如vip和非vip)在一个系统中只能使用指定的功能并且只能访问指定的界面,权限管理是一个项目当中必不可少的部分。

  1. 权限管理功能的实现原理

路由分为两块:

  1. 不需要权限访问的路由,比如登录页面、404页面,有时首页也不需要。

  1. 需要权限访问的路由

用户登录后后端会返回一个当前用户的权限标识,前端通过给定的权限标识筛选出用户能够访问的有权限的路由,先把筛选出来的有权限的路由通过 addRoutes 添加到实例上,目的是为了可以通过地址栏访问,然后把筛选出来有权限的动态路由存储到 vuex 中,目的是为了能够在菜单栏中体现。

注意:这里的 addRoutes 有一定的缺陷,它在导航守卫进行完一次后才会添加新配置的路由,所以需要让它再走一次导航守卫才能够使用。

  1. 整体流程

1.创建数据库表

users 用户表(要包含role字段,里面是对应的role表里的id值)

role 角色表 (具体有哪些角色,不同的角色有不同的权限)

2.实现登录功能

在登录页面输入用户名和密码,携带用户名和密码向服务端发送请求

<template></template>模板

  1. <div class="login-content">
  2. <div class="con-left">
  3. <div class="text">
  4. <p class="item1">车响汽车CRM系统</p>
  5. <p class="item2">CAR CRM SYSTEM</p>
  6. </div>
  7. </div>
  8. <el-form
  9. :model="ruleForm"
  10. status-icon
  11. :rules="rules"
  12. ref="ruleForm"
  13. label-width="100px"
  14. class="demo-ruleForm"
  15. >
  16. <h3>登录</h3>
  17. <el-form-item label="用户名" prop="username">
  18. <el-input
  19. type="username"
  20. v-model="ruleForm.username"
  21. autocomplete="off"
  22. ></el-input>
  23. </el-form-item>
  24. <el-form-item label="密码" prop="password">
  25. <el-input
  26. type="password"
  27. v-model="ruleForm.password"
  28. autocomplete="off"
  29. ></el-input>
  30. </el-form-item>
  31. <el-form-item>
  32. <el-button @click="resetForm('ruleForm')">重置</el-button>
  33. <el-button type="primary" @click="submitForm('ruleForm')">登录</el-button>
  34. </el-form-item>
  35. </el-form>
  36. </div>

<script></script>标签中

  1. <script>
  2. import { userLogin } from "@/api/request";
  3. //引入路由中定义的动态添加路由的函数
  4. import {asyncRoutes} from '@/router/index.js'
  5. export default {
  6. data() {
  7. return {
  8. ruleForm: {
  9. username: '',
  10. password: '',
  11. },
  12. rules: {
  13. username: [
  14. { validator: validateUsername, trigger: 'blur' }
  15. ],
  16. password: [
  17. { validator: validatePassword, trigger: 'blur' }
  18. ],
  19. }
  20. };
  21. },
  22. methods: {
  23. submitForm(formName) {
  24. this.$refs[formName].validate(async (valid) => {
  25. if (valid) {
  26. //验证用户名和密码
  27. let res = await userLogin(this.ruleForm);
  28. let {code,token,navData }=res.data;
  29. if(code==200){
  30. localStorage.setItem('token',token);
  31. localStorage.setItem("navData",JSON.stringify(navData));
  32. this.$store.commit("getNavData",navData)
  33. // 动态添加路由
  34. asyncRoutes();
  35. this.$message({
  36. message:'登录成功',
  37. type:'success'
  38. });
  39. this.$router.push('/home');
  40. }else{
  41. this.$message.error('登录失败');
  42. this.$refs[formName].resetFields();
  43. }
  44. } else {
  45. console.log('error submit!!');
  46. return false;
  47. }
  48. });
  49. },
  50. resetForm(formName) {
  51. this.$refs[formName].resetFields();
  52. }
  53. }
  54. }
  55. </script>

3.后端验证用户名和密码 获取身份,返回对应的路由信息

  1. express后端userLogin.js文件中
  2. let express=require("express");
  3. let userLogin=express.Router();
  4. const db = require("../service/db");
  5. const vartoken = require("../utils/token");
  6. let adminRoutes = require('../api/adminRoutes.json');
  7. let userRoutes = require('../api/userRoutes.json');
  8. let routers = {
  9. root:adminRoutes,//管理员身份的路由数据
  10. user:userRoutes//普通用户身份的路由数据
  11. }
  12. userLogin.post("/login",(req,res)=>{
  13. let {username,password} = req.body;
  14. let sql = `select * from users,role where users.role = role.id and username='${username}' and password='${password}'`;
  15. db.base(sql,null,(result)=>{
  16. if(result.length>0){
  17. // 4. 使用用户名生成token,将token进行返回
  18. // 生成token
  19. vartoken.setToken(username).then(token=>{
  20. data={
  21. code:200,
  22. msg:'登录成功',
  23. token:token,
  24. navData:routers[result[0].rolename],//返回对应角色的路由信息
  25. }
  26. res.send(data);
  27. })
  28. }else{
  29. // 3. 不正确,返回登录失败
  30. data={
  31. code:401,
  32. msg:'登录失败'
  33. }
  34. res.send(data);
  35. }
  36. })
  37. });
  38. module.exports=userLogin;
  1. 存储路由信息的json格式文件

以管理员的adminRoutes.json为例

  1. [
  2. {
  3. "path": "/market",
  4. "name": "market",
  5. "title": "营销管理",
  6. "icon": "el-icon-s-grid",
  7. "children": [
  8. {
  9. "path": "clue",
  10. "name": "clue",
  11. "url": "/Market/Clue",
  12. "title": "线索信息"
  13. },
  14. {
  15. "path": "activity",
  16. "name": "activity",
  17. "url": "/Market/Activity",
  18. "title": "活动管理"
  19. },
  20. {
  21. "path": "channel",
  22. "name": "channel",
  23. "url": "/Market/Channel",
  24. "title": "渠道管理"
  25. }
  26. ]
  27. },
  28. {
  29. "path": "/customer",
  30. "name": "customer",
  31. "title": "客户管理",
  32. "icon": "el-icon-s-custom",
  33. "url": "/Customer/CustList"
  34. },
  35. {
  36. "path": "/stock",
  37. "name": "stock",
  38. "title": "库存管理",
  39. "icon": "el-icon-s-order",
  40. "children": [
  41. {
  42. "path": "carlist",
  43. "name": "carlist",
  44. "url": "/Stock/CarList",
  45. "title": "车辆管理"
  46. },
  47. {
  48. "path": "waiting",
  49. "name": "waiting",
  50. "url": "/Stock/Waiting",
  51. "title": "排队库管理"
  52. }
  53. ]
  54. },
  55. {
  56. "path": "/finance",
  57. "name": "finance",
  58. "title": "财务管理",
  59. "icon": "el-icon-s-finance",
  60. "children": [
  61. {
  62. "path": "contract",
  63. "name": "contract",
  64. "url": "/Finance/Contract",
  65. "title": "合同管理"
  66. },
  67. {
  68. "path": "order",
  69. "name": "order",
  70. "url": "/Finance/Order",
  71. "title": "订单管理"
  72. }
  73. ]
  74. },
  75. {
  76. "path": "/notice",
  77. "name": "notice",
  78. "title": "发布活动",
  79. "icon": "el-icon-message-solid",
  80. "url": "/Notice/Notice"
  81. }
  82. ]

5.保存到vuex和localstorage中

1.生成路由

在index.js路由文件中

全局前置守卫中 获取数据

  1. //解决重新登录时,路由重复定义的报错
  2. const createRouter = () =>
  3. new VueRouter({
  4. routes,
  5. });
  6. const router = createRouter();
  7. //在重新登录时,重置路由对象
  8. function resetRouter() {
  9. const newRouter = createRouter();
  10. router.matcher = newRouter.matcher; // the relevant part
  11. }
  12. // 全局前置守卫
  13. router.beforeEach((to, from, next) => {
  14. document.title = to.meta.title;
  15. let token = localStorage.getItem("token");
  16. if (to.fullPath === "/login") {
  17. next();
  18. } else {
  19. if (token) {
  20. // 解决刷新页面时重新获取路由数据
  21. let navData = store.state.navData;
  22. if (navData.length === 0) {
  23. //如果长度为0,则是刷新
  24. // 从sessionStorage中拿navData数据
  25. navData = JSON.parse(localStorage.getItem("navData"));
  26. store.commit("getNavData", navData);
  27. asyncRoutes(navData);
  28. // 参考4.3.4解释
  29. next({ ...to, replace: true });
  30. } else {
  31. next();
  32. }
  33. } else {
  34. next("/login");
  35. }
  36. }
  37. });

遍历数据 放到router身上

  1. export function asyncRoutes() {
  2. resetRouter() //重置路由
  3. // 1.获取路由信息
  4. let navData = store.state.navData; //store中的动态路由菜单
  5. // 2. 处理路由信息
  6. navData.forEach(item => {
  7. let routeItem = {};
  8. if (item.children) {
  9. // 二级路由
  10. routeItem = {
  11. path: item.path,
  12. name: item.name,
  13. component: () => import('@/views/Layout'),
  14. redirect: item.path + '/' + item.children[0].path,
  15. meta: {
  16. title: item.title,
  17. },
  18. children: []
  19. }
  20. item.children.forEach(child => {
  21. routeItem.children.push({
  22. path: child.path,
  23. meta: {
  24. title: child.title
  25. },
  26. component: () => import('@/views' + child.url)
  27. })
  28. })
  29. } else {
  30. // 一级路由
  31. routeItem = {
  32. path: item.path,
  33. name: item.name,
  34. component: () => import('@/views/Layout'),
  35. meta: {
  36. title: item.title,
  37. leavel: 1,
  38. },
  39. children: [{
  40. path: item.path + item.path,
  41. meta: {
  42. title: item.title
  43. },
  44. component: () => import('@/views' + item.url)
  45. }]
  46. }
  47. }
  48. // 把拼接好的路由,放入到router中
  49. router.addRoute(routeItem);
  50. router.addRoute({
  51. path: '*',
  52. name: '404',
  53. meta: {
  54. title: '404页面'
  55. },
  56. component: () => import('../views/NotFound')
  57. });
  58. })
  59. }

2.生成侧边栏

1.在navmen.vue中获取数据 使用计算属性进行获取

  1. <script>
  2. export default {
  3. computed:{
  4. routerList(){
  5. return this.$store.state.navData;
  6. }
  7. }
  8. };
  9. </script>

2. 直接将值传给侧边栏子组件

  1. <template>
  2. <el-menu
  3.     :default-active="$route.fullPath"
  4.     class="el-menu-vertical-demo"
  5.     @open="handleOpen"
  6.     @close="handleClose"
  7.     background-color="#001529"
  8.     text-color="#fff"
  9.     active-text-color="#ffd04b"
  10.     :router="true" :collapse="iscollapse"
  11.     :collapse-transition="false" >
  12. <!-- 循环侧边栏 -->
  13. <el-menu-item index="/home">
  14. <i class="el-icon-s-home"></i>
  15. <span slot="title" v-if="!iscollapse">首页</span>
  16. </el-menu-item>
  17. <div v-for="item in routerList" :key="item.path" >
  18. <!-- 二级路由 -->
  19. <el-submenu :index="item.path" v-if="item.children">
  20. <template slot="title">
  21. <i :class="item.icon" tyle="width:40px;"></i>
  22. <span v-if="!iscollapse">{{ item.title}}</span>
  23. </template>
  24. <el-menu-item-group>
  25. <el-menu-item :index="item.path+'/'+child.path" v-for="child in item.children" :key="child.path">{{ child.title }}</el-menu-item>
  26. </el-menu-item-group>
  27. </el-submenu>
  28. <el-menu-item :index="item.path+item.path" v-else>
  29. <i :class="item.icon"></i>
  30. <span slot="title" v-if="!iscollapse">{{item.title}}</span>
  31. </el-menu-item>
  32. </div>
  33. </el-menu>
  34. </template>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/58831
推荐阅读
相关标签
  

闽ICP备14008679号