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

关于先后端分离开发中的权限处理问题,松哥以前写过一篇文章和你们聊这个问题:前端

可是最近有小伙伴在学习微人事项目时,对动态菜单这一块仍是有疑问(即不一样用户登陆成功后会看到不一样的菜单项),所以松哥打算再来写一篇文章和你们聊一聊先后端分离开发中的动态菜单问题。vue

1. 一个原则

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

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

这是很是重要的一点,作先后端分离开发中的权限管理,咱们首先要创建上面这样的思考框架,而后在这样的框架下,去考虑其余问题。json

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

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)的过程,赢了的一方就能够少写几行代码了。

关注公众号【江南一点雨】,专一于 Spring Boot+微服务以及先后端分离等全栈技术,按期视频教程分享,关注后回复 Java ,领取松哥为你精心准备的 Java 干货!

相关文章
相关标签/搜索