Spring Cloud + Vue前后端分离-第12章 通用权限设计

发布时间:2024年01月12日

?源代码在GitHub - 629y/course: Spring Cloud + Vue前后端分离-在线课程

Spring Cloud + Vue前后端分离-第12章 通用权限设计

这一章我们不依赖第三方框架,我会从权限相关表的设计,到权限的配置,到权限的拦截,带大家一步一步的做出一个通用的权限设计方案。

12-1 通用权限解决方案介绍

权限拦截的对象:用户

权限拦截的点:菜单、路由、接口、按钮

控制用户对资源的访问

权限的操作:配置、读取、拦截

100用户 * 100资源

直接用用户和资源做关联来控制权限,适合小型的项目,简单,快速

三个核心概念:用户、角色、资源

100用户 * 2个角色 + 2个角色 * 100资源

经典的权限管理设计:用户和角色关联,角色和资源关联

功能点:

配置:

????????用户管理:用户表,用户管理界面,已完成

????????资源配置:资源表,资源配置界面

????????角色管理:角色表,角色管理界面

????????用户角色关联配置:用户角色关联表,复用角色管理界面

????????角色资源关联配置:角色资源关联表,复用角色管理界面

两张关联表的配置,可以单独设计界面,也可以直接做到角色管理界面里。

读取:

? ? ? ? 用户权限的读取:用户登录的时候,读取该用户的所有权限。

登录时,通过用户角色关联表,可以知道当前登录用户的角色,再通过角色资源关联表就可以查到当前用户所有的资源

拦截:

? ? ? ? 用户操作业务时,进行权限拦截

? ? ? ? ? ? ? ? 前端界面:菜单,路由,按钮,hidden disabled

? ? ? ? ? ? ? ? 后端接口:接口,gateway的过滤器

疑问:前端已经对菜单和按钮做拦截,用户不能操作了,为什么还要对接口做拦截?

重要提示:所有前端的设计都是不安全的。

例登录名被修改了,说明我们的接口没有做登录名不可修改的校验,因为我们认为给登录名加了disabled就可以了,这是一个常见的安全隐患。

权限初始化

系统上线时,要初始化这五张表的数据。初始有一个用户能登录,能管理角色,管理资源,分配权限。

前面的章节的讲解模式是从简单的功能入手,再不断的扩展和完善,这一章,我们换一种模式,就会先分析需求,再列出功能点,明确总体要做哪些功能,再开始开发。

在实际工作中,也是用这种模式,我们还会加入团队评审的环节,确保我们的功能不会做歪了。

中高级面试题:请简单的设计一个权限管理功能,对初级人员来说会有点难,不过学完这一章,就不是问题了。

12-2 资源配置管理

资源表的设计与基本代码生成

1.通用权限管理:资源表的设计与基本代码生成

资源的名称一般是用页面上看得见的元素:菜单、按钮等。

all.sql

如果一个页面的所有操作统一控制权限,request可以填相关接口的前缀

生成代码

ResourceService.java报错原因:资源表的实体类是Resource和@Resource注解同名,导致冲突?

admin.vue

router.js

测试

资源树的保存

1.通用权限管理:资源树的保存

资源点是开发阶段就确定的,所以并不是上线后再一个一个配置的。

资源管理最简单的一种方案:上线前准备好sql,刷库。

将资源管理做成资源树进行管理。

填入数据:带有层级结构的json字符串

resource.json

用法:以后开发新功能的时候,就在该文件里加入新的资源,可以上线前将新的资源json通过控台保存进数据库。

resource.vue

ResourceDto.java

ResourceService.java

将节点一个一个的取出来,放入list中?

ResourceController.java

测试

资源树的显示

1.通用权限管理:资源树的显示

resource.vue

ResourceController.java

ResourceService.java

资源的保存是将树结构转成列表,重点是children属性;资源的显示是将列表转成树结构,重点是parent属性。

小知识:一边循环list,一边删除list中的对象,可以使用倒序循环。

list中有父节点的对象都会被remove掉,最终留下来的就是顶级的节点。

测试

12-3 角色权限管理

基本的角色管理功能

1.通用权限管理:增加基本的角色管理功能

2.资源列表补全

all.sql

admin.vue

router.js

resource.json

[{
  "id" : "01","name": "系统管理",
  "children": [{
    "id" : "0101","name": "用户管理","page": "/system/user",
    "children": [
      {"id": "010101","name": "保存","request": ["/system/admin/user/list","/system/admin/user/save"]},
      {"id": "010102","name": "删除","request": ["/system/admin/user/delete"]},
      {"id": "010103","name": "重置密码","request": ["/system/admin/user/save-password"]}
    ]
  },
    {
      "id" : "0102","name": "资源管理","page": "/system/resource",
      "children": [
        {"id": "010201","name": "保存/显示","request": ["/system/admin/resource"]}
      ]
    },{
      "id" : "0103","name": "角色管理","page": "/system/role",
      "children": [
        {"id": "010301","name": "角色/权限管理","request": ["/system/admin/role"]}
      ]
    }]
},
  {
    "id" : "02","name": "业务管理",
    "children": [{
      "id" : "0201","name": "分类管理","page": "business/category",
      "children": [
        {"id": "020101","name": "增删改查","request": ["/business/admin/category"]}
      ]
    },
      {
        "id" : "0202","name": "课程管理","page": "business/course",
        "children": [
          {"id": "020201","name": "增删改查","request": ["/business/admin/course",
            "/business/admin/category/all,/business/admin/teacher/list","/file/f/course","/business/chapter"]}
        ]
      },{
        "id" : "0203","name": "讲师管理","page": "business/teacher",
        "children": [
          {"id": "020301","name": "增删改查","request": ["/business/admin/teacher"]}
        ]
      }, {
        "id" : "0204","name": "大章管理","page": "business/chapter",
        "children": [
          {"id": "020401","name": "增删改查","request": ["/business/admin/course","/business/admin/chapter"]}
        ]
      },
      {
        "id" : "0205","name": "小节管理","page": "business/section",
        "children": [
          {"id": "020501","name": "增删改查","request": ["/business/admin/section","/business/admin/chapter"]}
        ]
      }
    ]
  },
  {
    "id" : "03","name": "文件管理",
    "children": [{
      "id" : "0301","name": "文件管理","page": "file/file",
      "children": [
        {"id": "030101","name": "文件管理","request": ["/file/admin/file","/file/admin"]}
      ]
    }]
  }
]

测试

增加角色资源关联功能

1.通用权限管理:增加角色资源关联功能表,生成持久层和服务端代码

all.sql

点击[关联资源]按钮时,加载资源树

1.通用权限管理:点击[关联资源]按钮时,加载资源树

role.vue

测试

点击资源树模态框【保存】按钮时,保存角色资源关联表

1.通用权限管理:点击资源树模态框【保存】按钮时,保存角色资源关联表

role.vue

RoleDto.java

RoleService.java

RoleController.java

测试

打开资源树模态框时,加载角色资源关联数据,并自动勾选树节点

1.通用权限管理:打开资源树模态框时,加载角色资源关联数据,并自动勾选树节点

role.vue

批量操作的思路:先将原有的删除,再批量新增

RoleService.java

RoleController.java

?测试

增加角色用户关联功能

1.通用权限管理:增加角色用户关联表,生成持久层和服务端代码

all.sql

点击【关联用户】按钮时,加载所有用户,弹出角色用户关联模态框

1.通用权限管理:点击【关联用户】按钮时,加载所有用户,弹出角色用户关联模态框

role.vue

测试

点击用户模态框【保存】按钮时,保存角色用户关联表

1.通用权限管理:点击用户模态框【保存】按钮时,保存角色用户关联表

role.vue

依赖vue的双向数据绑定特性,可以将复杂的页面操作变成简单的数据操作。很多前端框架都有双向数据绑定的特性,比如angular,微信小程序等。

RoleDto.java

RoleService.java

RoleController.java

测试

打开用户模态框时,加载角色用户关联数据

1.通用权限管理:打开用户模态框时,加载角色用户关联数据

role.vue

?查关联表,得到的时userId,但是显示需要的是loginName。这里也可以通过写自定义mapper,把user表和role_user表关联得到loginName

RoleService.java

RoleController.java

测试

12-4 登录时获取资源权限

读取当前登录用户所属的角色的所有资源

1.通用权限管理:登录时,读取当前登录用户所属的角色的所有资源

LoginUserDto.java

一个资源可以会用到多个接口,多个资源的接口就可能重复,所以这里用Set去重

MyUserMapper.xml

MyUserMapper.java

UserService.java

?测试

00000000

00000001?

00000002

?关于User的权限设置比较细,每个请求接口都可以单独控制。关于Resource的权限设置比较粗,所有接口用同一个request控制

12-5 权限拦截功能开发

前端界面权限拦截

前端界面权限拦截,完成用户管理

1.通用权限管理:前端界面权限拦截,完成用户管理

tool.js

admin.vue

在html中要使用vue方法,这个方法得在methods中定义

user.vue

测试

目前只修改了用户管理的权限拦截,以用户管理为例

00000000

每次修改权限配置,需要重新登录后才生效

前端界面权限拦截,完成所有界面控制

1.通用权限管理:前端界面权限拦截,完成所有界面控制

admin.vue

如果一个页面的所有按钮是统一控制的,那么只需要控制菜单就可以了,不需要给每个按钮加权限控制代码。

测试

路由权限判断

1.通用权限管理:前端界面权限拦截,增加路由权限判断

没有资源管理,但是我们可以直接通过路由进入

resource.json

[{
  "id" : "00","name": "欢迎","page": "welcome"
},{
  "id" : "01","name": "系统管理",
  "children": [{
    "id" : "0101","name": "用户管理","page": "system/user",
    "children": [
      {"id": "010101","name": "保存","request": ["/system/admin/user/list","/system/admin/user/save"]},
      {"id": "010102","name": "删除","request": ["/system/admin/user/delete"]},
      {"id": "010103","name": "重置密码","request": ["/system/admin/user/save-password"]}
    ]
  },
    {
      "id" : "0102","name": "资源管理","page": "system/resource",
      "children": [
        {"id": "010201","name": "保存/显示","request": ["/system/admin/resource"]}
      ]
    },{
      "id" : "0103","name": "角色管理","page": "system/role",
      "children": [
        {"id": "010301","name": "角色/权限管理","request": ["system/admin/role"]}
      ]
    }]
},
  {
    "id" : "02","name": "业务管理",
    "children": [{
      "id" : "0201","name": "分类管理","page": "business/category",
      "children": [
        {"id": "020101","name": "增删改查","request": ["/business/admin/category"]}
      ]
    },
      {
        "id" : "0202","name": "课程管理","page": "business/course",
        "children": [
          {"id": "020201","name": "增删改查","request": ["/business/admin/course",
            "/business/admin/category/all,/business/admin/teacher/list","/file/f/course","/business/chapter"]}
        ]
      },{
        "id" : "0203","name": "讲师管理","page": "business/teacher",
        "children": [
          {"id": "020301","name": "增删改查","request": ["/business/admin/teacher"]}
        ]
      }, {
        "id" : "0204","name": "大章管理","page": "business/chapter",
        "children": [
          {"id": "020401","name": "增删改查","request": ["/business/admin/course","/business/admin/chapter"]}
        ]
      },
      {
        "id" : "0205","name": "小节管理","page": "business/section",
        "children": [
          {"id": "020501","name": "增删改查","request": ["/business/admin/section","/business/admin/chapter"]}
        ]
      }
    ]
  },
  {
    "id" : "03","name": "文件管理",
    "children": [{
      "id" : "0301","name": "文件管理","page": "file/file",
      "children": [
        {"id": "030101","name": "文件管理","request": ["/file/admin/file","/file/admin"]}
      ]
    }]
  }
]

?admin.vue

第一次加载admin.vue时,需要判断路由权限,比如从登录页跳到控台主页,或者刷新控台主页时,会执行mounted.

进入控台主页后,发生子路由跳转时,会触发watch。

测试

后端接口权限判断

1.通用权限管理:增加后端接口权限拦截

在做登录功能时,我们也对接口做了登录校验,否则容易被绕开登录,直接调用后端接口。这里同样需要对接口做权限拦截

重新登录?

可以通过搜索hidden,display:none等,来查看页面是否有隐藏元素

ctrl+f

?可以删除成功,这是非常危险的

?LoginAdminGatewayFilter.java

gateway里没有饮用server模块,所以没用LoginUserDto类。这里转成JSONObject进行操作

比如资源的保存:

path=system/admin/resource/save,

而配置的

request=system/admin/resource,

那么path.contain(request)就是true

测试

可以在vue的拦截器中,针对401返回码做判断,如果是401,就跳到登录页面

将业务场景变成程序代码

需求分析:最终要做成什么样子,如何使用这个功能。

功能点拆分:要实现这个需求,都有哪些功能点。

代码编写

团队内部评审通过后,为每个功能点评优先级,并估工时。

每天早上开展例会,每个人花几分钟的时间回答3个问题:

1.昨天做了哪些内容;

2.有没有遇到什么问题;

3.今天准备做哪些内容。

有问题一定要反馈出来,可以是遇到新技术了,或是功能点比想象中复杂,工时估少了等等。

文章来源:https://blog.csdn.net/qq_52963857/article/details/135182321
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。