前后端分离开发中动态菜单的两种实现方案

更新日期: 2019-09-11阅读: 2.3k标签: 菜单

1. 一个原则

做权限管理,一个核心思想就是后端做权限控制,前端做的所有工作都只是为了提高用户体验,我们不能依靠前端展示或者隐藏一个按钮来实现权限控制,这样肯定是不安全的。

就像用户注册时需要输入邮箱地址,前端校验之后,后端还是要校验,两个校验目的不同,前端校验是为了提高响应速度,优化用户体验,后端校验则是为了确保数据完整性。权限管理也是如此,前端按钮的展示/隐藏都只是为了提高用户体验,真正的权限管理需要后端来实现。

这是非常重要的一点,做前后端分离开发中的权限管理,我们首先要建立上面这样的思考框架,然后在这样的框架下,去考虑其他问题。

因此,下文我会和大家分享两种方式实现动态菜单,这两种方式仅仅只是探讨如何更好的给用户展示菜单,而不是探讨权限管理,因为权限管理是在后端完成的,也必须在后端完成。


2. 具体实现

一旦建立起这样的思考框架,你会发现动态菜单的实现办法太多了。

动态菜单就是用户登录之后看到的菜单,不用角色的用户登录成功之后,会看到不用的菜单项,这个动态菜单要怎么实现呢?整体来说,有两种不同的方案,松哥曾经做过的项目中,两种方案也都有用过,这里分别来和大家分享一下。

2.1 后端动态返回

后端动态返回,这是我在微人事中采用的方案。微人事中,权限管理相关的表一共有五张表,如下:

其中 hr 表就是用户表,用户登录成功之后,可以查询到用户的角色,再根据用户角色去查询出来用户可以操作的菜单(资源),然后把这些可以操作的资源,组织成一个 JSON 数据,返回给前端,前端再根据这个 JSON 渲染出相应的菜单。以微人事为例,我们返回的 JSON 数据格式如下:

[
    {
        "id":2,
        "path":"/home",
        "component":"Home",
        "name":"员工资料",
        "iconCls":"fa fa-user-circle-o",
        "children":[
            {
                "id":null,
                "path":"/emp/basic",
                "component":"EmpBasic",
                "name":"基本资料",
                "iconCls":null,
                "children":[

                ],
                "meta":{
                    "keepAlive":false,
                    "requireAuth":true
                }
            }
        ],
        "meta":{
            "keepAlive":false,
            "requireAuth":true
        }
    }
]

这样的 JSON 在前端中再进行二次处理之后,就可以使用了,前端的二次处理主要是把 component 属性的字符串值转为对象。这一块具体操作大家可以参考微人事项目(具体在:https://github.com/lenve/vhr/blob/master/vuehr/src/utils/utils.js),我就不再赘述了。

这种方式的一个好处是前端的判断逻辑少一些,后端也不算复杂,就是一个 SQL 操作,前端拿到后端的返回的菜单数据,稍微处理一下就可以直接使用了。另外这种方式还有一个优势就是可以动态配置资源-角色以及用户-角色之间的关系,进而调整用户可以操作的资源(菜单)。


2.2 前端动态渲染

另一种方式就是前端动态渲染,这种方式后端的工作要轻松一些,前端处理起来麻烦一些,松哥去年年末帮一个律所做的一个管理系统,因为权限上比较容易,我就采用了这种方案。

这种方式就是我直接在前端把所有页面都在路由表里边定义好,然后在 meta 属性中定义每一个页面需要哪些角色才能访问,例如下面这样:

[
    {
        "id":2,
        "path":"/home",
        "component":Home,
        "name":"员工资料",
        "iconCls":"fa fa-user-circle-o",
        "children":[
            {
                "id":null,
                "path":"/emp/basic",
                "component":EmpBasic,
                "name":"基本资料",
                "iconCls":null,
                "children":[

                ],
                "meta":{
                    "keepAlive":false,
                    "requireAuth":true,
                    "roles":['admin','user']
                }
            }
        ],
        "meta":{
            "keepAlive":false,
            "requireAuth":true
        }
    }
]

这样定义表示当前登录用户需要具备 admin 或者 user 角色,才可以访问 EmpBasic 组件,当然这里不是说我这样定义了就行,这个定义只是一个标记,在项目首页中,我会遍历这个数组做菜单动态渲染,然后根据当前登录用户的角色,再结合当前组件需要的角色,来决定是否把当前组件所对应的菜单项渲染出来。

这样的话,后端只需要在登录成功后返回当前用户的角色就可以了,剩下的事情则交给前端来做。不过这种方式有一个弊端就是菜单和角色的关系在前端代码中写死了,以后如果想要动态调整会有一些不方便,可能需要改代码。特别是大项目,权限比较复杂的时候,调整就更麻烦了,所以这种方式我一般建议在一些简单的项目中使用。


3. 结语

虽然我在微人事中使用了第一种方式,不过如果小伙伴是一个新项目,并且权限问题不是很复杂的话,我还是建议尝试一下第二种方式,感觉要方便一些。

不过在公司中,动态菜单到底在前端做还是后端做,可能会有一个前后端团队沟(si)通(bi)的过程,赢了的一方就可以少写几行代码了。


链接: https://fly63.com/article/detial/5841

HTML下拉导航菜单的实现:CSS/Js的实现方案

熟练使用导航栏,对于网站排版非常重要,使用CSS,js,jq等你可以转换成好看的导航栏而不是枯燥的HTML菜单。

Flutter实现仿微信QQ侧滑菜单组件

1. 首先可以滑出菜单 2. 菜单滑动到一定距离完全滑出,未达到距离回滚 3. 菜单数量、样式随意定制 4. 菜单点击回调 5. 菜单展开时,点击 item 收回菜单,需求明了以后就可以写代码了。

简单的树形菜单如何写?

数据结构中含有图片、名称、children的树形结构,需要展示出每一级的图片名称和图片,找了些树形图的插件,都没有展示大的图片的,一般都是小图标,就自己试着写一个包含图的简单的插件。

vue项目中的菜单权限控制

在pc 管理系统这种类型的产品,通常会涉及到账号权限的控制,不同的账号权限能浏览的功能模块是不同的,对应侧边栏菜单模块的显示也会不同。单点登录类系统,通常会多个项目公用一套登录系统,项目首页直接就是dashboard 或者 index页面

CSS多级菜单的实现

这是一个相当炫的功能,让网页看起来像桌面程序,如window的开始菜单。实现原理基本和纯CSS相册差不多,但要注意的事项比较多,让我们一步步来吧。

vue-contextmenujs原生右键菜单组件

vue-contextmenujs:Vue 原生实现右键菜单组件, 零依赖;npm 安装npm install vue-contextmenujs;测试中使用的是element-ui图标 ;

在Vue中实现随hash改变响应菜单高亮

Vue+Element 实现管理页面菜单栏, 点击菜单时 router 改变 hash 访问不同子组件。但是改变 hash 时菜单栏展开状态和 highlight 并不会同步, 需要手动实现。

Vue3 封装 Element Plus Menu 无限级菜单组件

本文分别使用 SFC(模板方式)和 tsx 方式对 Element Plus el-menu 组件进行二次封装,实现配置化的菜单,有了配置化的菜单,后续便可以根据路由动态渲染菜单。

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!