0

vue前后端分离后台管理系统(权限管理,登录),对接后端SpringSecurity,实现权限管...

 2 years ago
source link: https://blog.csdn.net/grd_java/article/details/122783691
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、重要知识点总结以及登录功能实现

由于篇幅原因,我将其放在这个文章中:https://blog.csdn.net/grd_java/article/details/122770777

二、权限管理菜单的增删改查实现

我们先实现整个的增删改查功能,最后再实现权限功能,很简单,直接看上面码云源码就好,下面是效果演示
  1. 用户管理
    在这里插入图片描述
    在这里插入图片描述
  2. 角色管理
    在这里插入图片描述
    在这里插入图片描述
  3. 菜单管理
    在这里插入图片描述

1. 路由配置

配置效果如下

在这里插入图片描述

先把相关组件创建完成,创建出来就好,把首页的index.vue文件复制3份即可

在这里插入图片描述

配置路由

在这里插入图片描述

// 2.所有路由都封装到这个常量中
export const constantRoutes = [
  {
    path: '/login',
    component: () => import('@/views/login/index'),
    hidden: true
  },

  {
    path: '/404',
    component: () => import('@/views/404'),
    hidden: true
  },

  {
    path: '/',
    component: Layout,
    redirect: '/dashboard',
    children: [{//这里的内容会在<router-view :key="key" />标签渲染
      path: 'dashboard',
      name: 'Dashboard',
      component: () => import('@/views/dashboard/index'),
      meta: { title: '首页', icon: 'dashboard' }
    }]
  },

  {
    path: '/security',
    component: Layout,
    redirect: '/security/user',
    meta: { title: '权限管理', icon: 'el-icon-lock' },
    children: [
      {
        path: 'user',
        name: 'User',
        component: () => import('@/views/security/user/index'),
        meta: { title: '用户管理'}
      },
      {
        path: 'role',
        name: 'Role',
        component: () => import('@/views/security/role/index'),
        meta: { title: '角色管理'}
      },
      {
        path: 'menu',
        name: 'menu',
        component: () => import('@/views/security/menu/index'),
        meta: { title: '菜单管理'}
      },
    ]
  },

  // 404 page must be placed at the end !!!
  { path: '*', redirect: '/404', hidden: true }
]

2. 用户管理功能

2.1 后端接口API介绍

  1. 根据所传json,查询符合条件的用户,json为空,显示所有,post请求.另外,还提供了一个处理分页的接口,也可以查询符合条件的用户
    在这里插入图片描述
    在这里插入图片描述
  2. put请求,表示根据json修改用户,但是不会修改密码
    在这里插入图片描述
  3. put请求,根据用户id和密码,修改用户密码
    在这里插入图片描述
  4. delete请求,根据id删除用户
    在这里插入图片描述
  5. put请求,更新用户所有角色,uid为用户id,rids是一个数组,表示角色,这里选择的角色将成为指定用户的角色
    在这里插入图片描述
  6. post请求,添加用户
    在这里插入图片描述

2.2 前端api接口

在这里插入图片描述

2.3 页面和逻辑编写

在这里插入图片描述

3. 角色管理功能

后端接口如下

在这里插入图片描述

前端相关文件

在这里插入图片描述
在这里插入图片描述

3.1 数据回显

如果当前用户拥有自己的菜单,我们点击修改菜单按钮后,需要将当前角色已有菜单,做数据回显,思路如下图难点:回显后,用户操作数据,需要和回显数据结合。当用户没有点击确定修改按钮做什么处理
  1. 拿到当前用户id,先清除回显数据,然后请求数据,完成数据回显。这样用户没有点击修改按钮,下次进入,依然是实时数据
    在这里插入图片描述
    在这里插入图片描述
  2. 点击修改按钮
    在这里插入图片描述

4. 菜单管理功能

除了处理树形数据有点难度外,其它大家自己去看源码就好

4.1 树形结构数据处理算法

在这里插入图片描述
在这里插入图片描述

将扁平数据换成树形结构
/**
 * 构造树型结构数据
 * @param {*} source 数据源
 * @param {*} id id字段 默认 'id'
 * @param {*} parentId 父节点字段 默认 'parentId'
 * @param {*} children 孩子节点字段 默认 'children'
 * @param {*} rootId 根Id 默认 0
 */
export function treeData (source, id, pid, children, rootId) {
  id = id || 'id'
  pid = pid || 'pid'
  children = children || 'children'
  rootId = rootId || 0
  const cloneData = JSON.parse(JSON.stringify(source))// 对源数据深度克隆
 return cloneData.filter(father => {
    const branchArr = cloneData.filter(child => father[id] == child[pid])// 返回每一项的子级数组
    branchArr.length > 0 ? father[children] = branchArr : delete father[children]// 如果存在子级,则给父级添加一个children属性,并赋值
    return father[pid] == rootId // 返回第一层
  })
}
树形结构数据转换为扁平数据
/**
 * 树形结构解析,构造为普通形式
 */
export function unTreeData(source,children){
  children = children || 'children'
  let cloneData = JSON.parse(JSON.stringify(source))// 对源数据深度克隆
  let arr = []//保存最终结果
  unTreeDatadd(cloneData,children,arr)//递归解析树结构,解析结果放在arr中
  return arr;//将arr返回
}
function unTreeDatadd(source,children,arr){
  //遍历数组
  source.filter(father=>{
    if(father[children]){//如果当前元素有child,将当前元素加入arr,然后递归它的儿子加入arr,儿子都递归完,删除当前元素的children属性
      arr.push(father)//将当前元素加入arr
      unTreeDatadd(father[children],children,arr)//递归儿子
      delete father[children]//删除children
    }else{//如果当前元素没有child
      arr.push(father)//直接添加到arr
    }
  })
}

三、权限控制功能实现

效果展示:
  1. admin用户登录
    在这里插入图片描述
  2. 作者用户登录
    在这里插入图片描述
后端的针对url的已经完成了权限控制,所以我们前端不做任何实现,一个用户也没有办法操作它没有权限的内容(直接报权限不足异常)。但是这样用户体验不好,所以我们最好让一个用户没有权限操作的东西,直接不显示,思路如下:
  1. 当用户登录成功后,根据用户id查询它拥有的角色,和菜单权限,保存到vuex中
  2. 将路由拆分(把原来完整的进行拆分)
  1. 常量路由:无论何种用户,都可以操作的路由,比如登录,首页。
  2. 异步路由:根据不同用户,展示不同的路由。注意,路由不是从服务器获取到的,服务器返回的只是一个标识,我们需要进行比对,隐藏不需要的路由
  3. 任意路由:404等路由,用户操作错了,从定向的路由
  1. 获取异步路由,我们需要通过异步路由,进行比较过滤,判断哪些路由不需要显示
如何判断呢
  1. 对于路由,我们主要通过查询数据库配置的菜单,取出path属性,与前端的路由进行比较,过滤前端的路由,path相同的路由,会显示,path不同的路由会被过滤
    在这里插入图片描述
    在这里插入图片描述

1. 拆分路由

1. 常量路由

在这里插入图片描述

2. 异步和任意路由

在这里插入图片描述

2. 将用户角色和菜单权限保存到vuex,然后过滤路由

1. 引入我们需要的东西和state

在这里插入图片描述

2. mutations方法,合并路由,挂载到router

在这里插入图片描述

3. 获取用户信息成功后,获取用户菜单,将角色和菜单封装到vuex

在这里插入图片描述

4. 过滤异步路由

在这里插入图片描述

//比较路由,返回需要展示的异步路由
const compareasyncRoutes = (asyncRoutes,routes)=>{
  return asyncRoutes.filter(item =>{
    if(routes.indexOf(item.path)!=-1){//如果当前路由,用户拥有权限,就展示
      if(item.children&&item.children.length){//如果有children就递归
        item.children = compareasyncRoutes(item.children,routes)
      }
      return true;
    }
  })
}

3. 使用模板需要做的额外更改

完成上面的内容后,已经完成了路由的权限控制,但是我们使用的模板,只使用了常量路由,所以我们需要修改
  1. 如下可看到,模板中使用的是常量路由
    在这里插入图片描述
修改代码,让它使用vuex中的路由

在这里插入图片描述

此时并没有完事,进入路由后,刷新页面会丢失数据

在这里插入图片描述

4. 解决刷新页面vuex中数据丢失,路由丢失问题

很简单,通过路由导航,切换路由时判断vuex中数据是否存在,如果不存在,说明刷新了页面,需要重新生成路由

在这里插入图片描述

/**动态路由需要解决,刷新路由丢失问题**/
    //判断是否为刷新页面,vuex中无数据,则为刷新页面
    if(store.state.user.routesResult.length === 0 ){
      // 获取用户信息(关于异步路由的东西我放这里了)
      store.dispatch('user/getInfo').then(()=>{
        next({path:to.path})
      })
    }else{
      next()
    }

四、按钮权限控制

如果用户可以浏览某页面,但是没有某按钮权限,那么将无法看到此按钮,效果如下:
  1. 需要设定浏览权限(因为我们使用element ui组件,它没法直接选父菜单,)
    在这里插入图片描述
  2. 超级管理员的权限
    在这里插入图片描述
  3. 普通用户的权限
    在这里插入图片描述
  4. 超级管理员看到的页面
    在这里插入图片描述
  5. 普通用户看到的页面
    在这里插入图片描述

1. 修改element ui 源码解决问题

我们上面通过人为多添加一个显示权限,解决了父菜单无法直接选中的问题

在这里插入图片描述
在这里插入图片描述

另外还可以修改element ui 源码,修改方法看下面注释,我这里选用上面的方法

在这里插入图片描述

2. 实现按钮权限

分析
  1. 通过菜单权限来判断
    在这里插入图片描述
  2. 只需要判断就可以了
vuex 封装

在这里插入图片描述

相应按钮添加判断

在这里插入图片描述

<el-button type="primary" slot="reference" v-show="$store.state.user.buttons.indexOf('btn:security')!=-1">添加</el-button>
效果
  1. 超级管理员看到的页面
    在这里插入图片描述
  2. 普通用户看到的页面
    在这里插入图片描述

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK