Blogger Information
Blog 29
fans 1
comment 0
visits 35390
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
基于ThinkPHP6.0的一个通用后台管理系统
祥子弟弟
Original
2639 people have browsed it

RBAC(角色访问控制)设计模型的后台管理系统

RBAC 是一套成熟的权限模型,元素包括:用户、角色、权限。在 RBAC 模型中,权限与角色相关联,用户通过成为对应角色的成员,从而得到这些角色的权限。即用户关联角色,角色关联权限,可实现系统权限的灵活配置。在本篇文章介绍到的后台管理系统中,角色-用户是一对多的关系。

在本项目中前端框架使用的是 adminLTE,可以在本项目目录文件的 public 文件夹下找到。
数据库是 MySQL,一共有 6 张数据表(本来是 4 张的,后边加了个文章管理,多了个文章和文章分类表)

项目模块

1. 登录/退出模块

主要实现了登录和退出功能还有非法访问的功能。
由于是一个后台管理系统,所以没有涉及注册模块。作为一个登陆页面,而且是一个后台管理的登录页面,那么就不必那么的花哨,尽量的简洁美观就行,你可以给它起一个好听的名字,“xxx 后台管理”之类的。

接下来就是它需要实现的功能了,登录页面的逻辑是很简单的:

前端要做的就是给用户一个登录登录框,其中有用户名和密码以及验证码(注意:这里只是我想要的是让用户是用户名密码登录,你可以去设计其他的,可以是邮箱呀之类的等等),在前端的验证码这块儿使用的是 ThinkPHP 的一个扩展框架,topthink/think-captcha ,你可以直接在你的项目目录下使用 composer 命令直接去将它加载进来。在密码和用户名还有验证码验证这块儿是用的jquery-validation,后边涉及到的表单验证都是使用的它,对于验证消息,我使用了 layui 的弹出层组件layer,后边的所有的提示消息,警告消息都是使用的layer
验证码这块儿是需要注意的,如果你想要去重新定义或者说是设置你的验证码,你可以在 config 目录下的 captcha.php 中去添加一个额外的验证码信息,然后在 Login 控制器下重新定义一个公共方法,让它去完成重新生成验证码的功能。如果你像我一样重新定义了验证码的话,那么你就会发现重新刷新页面后,你的验证码点击之后是无法进行刷新的,惊不惊喜,意不意外。这时候,你先不要着急,可以先不去用自定义的验证码,回到原来的验证码,看看点击之后页面之中会有什么样的变化,你会发现它的查询字符串是会变化的,它后边多了个 id,这时候是不是就醒悟了呢,你可以给这张验证码图片添加一个点击事件,点击之后重新的设置它的 src 属性的值就行。这样验证码的问题就解决了。

后端要做的就是将用户输入的信息获取到,然后再数据库中查找信息,找到之后去判断用户名和密码是否匹配,如果不匹配,就需要返回一个错误信息了,这个错误信息最好是一个模糊信息,最好就是”用户名或密码不正确” 而不是指出哪一个不正确。如果匹配的结果是成功的,那么你就需要将当前的到的用户名和数据表中查询到的用户 id 放到 Session 中了,tp6 中默认是关着的,你需要在全局中间件定义文件 middleware.php 中将它开启,开启之后你就可以使用 Session 了,因为在非法访问功能中会用到当前登录的用户信息。

我们还需要一个中间控制器,这个中间控制器继承自 BaseController,这个中间控制器的作用就是非法访问(没有登陆成功的不允许访问,直接访问非登录页面强制跳转到登陆页面)登录之后的权限认证(如果当前用户不具有这个功能的权限,会直接给个弹窗,然后返回到上一个页面),在登录之后才能访问的页面都要继承自这个中间控制器,这样就做到了非法访问的功能。

2.主页面模块

主页面的前端页面我用的是 adminLTE 中的 index.html 来修改的,它需要做到的效果就是能够根据不同的用户登录,然后自动去渲染菜单栏,还有用户的退出登录和清除缓存的功能。

自动渲染无限级菜单:这个就需要去数据库中获取对应角色的权限了,然后再根据角色对用户进行权限绑定,然后还需要一个无限级菜单的划分,这样对于数据的处理就可以传到前端进行渲染了。最难的部分应该就是无限级菜单的划分了,这个就得根据数据表中的数据是怎样的来设计处理函数了,我的菜单数据表中的有一个 pid 字段,它代表着当前菜单的上级菜单的 id 值,就可以对当前用户所具有的权限来进行查询,获取到他的权限字段的数据,然后再对这些权限根据菜单表中的 pid 字段进行处理,就可以得到一个想要的数据了。

  1. // 无限级分类--循环一级导航和子导航,将结果组合成一个多维数组
  2. public static function ruleLayer($rule, $pid=0): array
  3. {
  4. // 声明一个空数组,用来存放生成的多维数组
  5. $rules = array();
  6. foreach ($rule as $vl){
  7. // 判断当前的菜单是否是主菜单
  8. if ($vl['pid'] == $pid){
  9. // 如果是主菜单,就给它添加一个child字段,然后将所有pid===它的id的所有菜单赋给这个child字段
  10. $vl['child'] = static::ruleLayer($rule, $vl['id']);
  11. $rules[] = $vl;
  12. }
  13. }
  14. return $rules;
  15. }

前端渲染就可以使用 tp6 自己封装的 volist,然后进行二级菜单的渲染。

退出登录:这是一个很简单的逻辑实现,点击退出登录后,在后端将 session 中的数据清空,然后再将页面重新定向到登陆页面就可以了,可以使用 redirect()函数进行操作。

清除缓存:清除缓存,在 tp6 中就是清除掉 runtime 目录下的当前应用所产生的日志文件,还有一些缓存数据,这个操作就有些麻烦了,因为 rmdir()函数它只能删除一个空的文件夹,也就是说,想要删除一个文件夹,你得将这个文件夹下的所有内容全部的删掉,首先要获取到当前的应用的运行目录,可以直接使用 tp6 封装的助手函数来获取,app()->getRuntimePath();,然后再对当前文件夹下的内容进行删除,具体函数实现如下.

  1. function delete_dir_file($dir)
  2. {
  3. // 声明一个初始状态,默认情况下缓存未被删除
  4. $res = false;
  5. // 检验一个目录是否真实
  6. if (is_dir($dir)){
  7. // 成功打开目录流,返回值是一个resource类型数据,如果不成功,返回false
  8. if ($handle = opendir($dir)){
  9. while (($file = readdir($handle)) != false){
  10. // echo "filename: " . $file . "<br>";
  11. /*
  12. * filename: . 代表当前访问目录存在同级目录
  13. * filename: .. 代表存在上级目录
  14. * filename: log 子目录
  15. * filename: session 子目录
  16. * filename: temp 子目录
  17. */
  18. if ($file !== '.' && $file !== '..'){
  19. // 判断是否是一个目录
  20. if (is_dir($dir . '\\' . $file)){
  21. // 拼接目录
  22. // 目录只有为空的情况下才能删除
  23. delete_dir_file($dir . '\\' . $file);
  24. }else{
  25. // 不是目录的情况,直接删除
  26. // unlink只能删除一个文件
  27. unlink($dir . '\\' . $file);
  28. }
  29. }
  30. }
  31. }
  32. // 关闭目录句柄
  33. closedir($handle);
  34. // 目录为空时删除目录
  35. if ($dir !== "E:\\Visual Studio Code\\harbor\\tp\\runtime\\admin\\session\\"){
  36. if (rmdir($dir)){
  37. $res = true;
  38. }
  39. }
  40. }
  41. return $res;
  42. }

在主页面还可以将当前登录的用户信息也渲染出来,获取到当前 session 中的值,然后渲染到页面中.

3.用户管理模块

用户管理模块的数据显示这里我使用了 DataTables 表格插件,它是一款 jquery 表格插件,可以在DataTables 中文网查看它的使用教程。
用户管理模块主要是实现了用户的新增,编辑,删除功能,对于角色是超级管理员的用户,设置了不允许修改自己的权限还有不允许创建一个新的超级管理员。

对于用户管理模块首页的数据渲染,由于只涉及到了一张表,所以只需要注意 DataTables 插件要求返回的数据就行了,然后从数据库中取出查到的数据,返回给前端页面来进行渲染,如果在 DataTables 中设置了分页和排序要求,那么在设计数据库查询语句的时候就必须要添加上。

用户新增:用户新增涉及到两张数据表,一张是用户表,一张是用户-角色关联表,首先在前端页面的显示时,需要将角色表中的角色信息全部都获取出来,然后将获取到的角色信息传给前端进行一个下拉列表的渲染,然后就是前端进行添加一个新的用户操作,然后将数据 post 给后端,后端接收到数据之后,需要对用户名进行查重判断,如果不重复,先更新用户表,再更新用户-角色关联表,用户-角色关联表是在用户表更新成功的前提下进行更新的。如果重复,直接退出脚本,返回给前端一个信息,重定位到用户名那里。

用户编辑:用户编辑同样的涉及到了两张表,用户表和用户-角色关联表,编辑的时候需要获取到当前编辑的用户信息,然后渲染到页面,所以,可以通过 get 方法,将当前编辑的用户的 uid 传给后端,然后后端在数据库中查找记录,然后返回给前端进行渲染。更新的时候可新增一样,需要先对用户表进行更新,如果更新成功,再去对用户-角色关联表进行更新。

用户删除:也涉及到两张表,用户表和用户-角色关联表,再点击删除后,需要给用户一个提示信息,让他确定是否删除,然后再对删除方法进行调用,删除之后,给用户一个删除成功提示。

4.规则管理模块

规则管理是对菜单页面的显示,新增一级菜单,新增子菜单,编辑菜单还有删除菜单功能的实现。规则管理同样的使用了 DataTables 表格插件,不过对于上级菜单和子菜单如果需要进行效果展示的话,就需要对菜单进行无限级菜单处理,经过无限级菜单分类之后,就可以将数据传到前端进行渲染了。

  1. // 无限级菜单分类, 前端规则列表分类
  2. public static function RuleList($rule, $pid=0, $lev=1): array
  3. {
  4. $arr = array();
  5. foreach ($rule as $r){
  6. if ($r['pid'] == $pid){
  7. $r['lev'] = $lev;
  8. $arr[] = $r;
  9. $arr = array_merge($arr, static::RuleList($rule, $r['id'], $lev+1));
  10. }
  11. }
  12. return $arr;
  13. }

新增菜单:新增菜单这块儿有两个选择,一个是新增一个一级菜单,一个是新增一个子菜单,新增子菜单的时候是点击每个菜单规则后边的按钮,新增一级子菜单的时候是点击最上边的新增按钮,两个按钮唯一不同的地方是在新增子菜单的地方,get 时候的参数不同,子菜单的 url 的查询语句中增加了 pid,然后就可以在后端接收的时候进行检查,如果 get 到 pid 那就是新增一个子菜单,如果没有那就是新增一个一级菜单。

编辑菜单:编辑菜单需要获取到当前菜单的 id,然后在数据库中查找到当前菜单的信息,返回前端进行渲染,然后用户修改当前规则信息,返回数据给后端,后端将修改后的信息更新到数据库中去。

删除菜单:删除菜单和删除角色的功能类似,不过是删除菜单只涉及到一张数据表,只需要对一张数据表中的数据进行删除就可以了,删除菜单首先要做的就是查询当前菜单下有没有子菜单,将 id 当作 pid 传入数据表中进行查询,如果存在,就不能进行删除。

5.角色管理模块

角色管理模块中最难的就是一个 checkbox 复选框的处理,角色模块包括了角色的删除,新增和编辑,删除角色和上边的思路是一样的,而编辑和添加就不一样了,编辑和添加需要做到的是,首先在前端页面中需要将所有的规则列举出来,要有层级感,在编辑的时候需要对当前角色所拥有的权限全部都选中。同样,在后端获取到所有的菜单信息时,要对数据进行无限级菜单的处理,然后再传入前端进行渲染。

6.数据库模块

本项目目前一共涉及到 6 张表,其中有 4 张表是现在用到的,另外两张表是我添加的扩展功能所设计的数据表,现在用到的表有: 1. 用户表“users”,2. 角色表“auth_role”,3. 规则表“auth_rule”, 4. 角色-用户关联表“users_role”.

本项目的所有源码都可在 Git 上查看。

点击这里查看源码

Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post