MYBLOG

0XFF编程网

对于后台管理系统,权限管理是最基本的一共功能, 一般会涉及3个概念 用户 角色 权限,今天将和大家分享一个最基本的权限设计, 涉及到4个表

  • 用户表user

  • 角色表role

  • 权限表rule

  • 角色-权限表role_rule

因角色标识直接记录在user 表中的role_guid 字段,所有没有设计user_role表.

数据库设计

用户表user

字段类型描述
guidchar(36)用户唯一标识 主键
parent_guidchar(36)父级菜单唯一标识
accountvarchar(100)登陆账号
namevarchar(100)用户姓名
passwordvarchar(100)登陆密码
role_guidchar(36)角色唯一标识
statustinyint(2)状态
create_timedatetime(3)创建时间
update_timedatetime(3)更新时间
delete_timedatetime(3)删除时间
DROP TABLE IF EXISTS `user`;CREATE TABLE `user`  (
  `guid` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
  `account` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '工号',
  `name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户姓名',
  `password` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户密码',
  `role_guid` char(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色唯一标识',
  `status` tinyint(2) NOT NULL DEFAULT 0 COMMENT '是否启用',
  `tel` char(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '电话号码',
  `create_time` datetime(3) NOT NULL COMMENT '创建时间',
  `update_time` datetime(3) NOT NULL COMMENT '更新时间',
  `delete_time` datetime(3) NULL DEFAULT NULL COMMENT '删除时间',
  PRIMARY KEY (`guid`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;SET FOREIGN_KEY_CHECKS = 1;

角色表role

字段类型描述
guidchar(36)角色唯一标识 主键
typetinyint(2)登陆账号
namevarchar(100)用户姓名
statustinyint(2)状态
create_timedatetime(3)创建时间
update_timedatetime(3)更新时间
delete_timedatetime(3)删除时间
DROP TABLE IF EXISTS `role`;CREATE TABLE `role` (
  `guid` char(36) NOT NULL,
  `type` tinyint(2) NOT NULL DEFAULT '2' COMMENT '1管理员,2操作员',
  `name` varchar(32) NOT NULL COMMENT '角色名称',
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否启用',
  `remark` varchar(255) DEFAULT '' COMMENT '简单说明',
  `delete_time` datetime DEFAULT NULL COMMENT '删除时间',
  `create_time` datetime(3) DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime(3) DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`guid`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='角色表';

权限表rule

字段类型描述
guidchar(36)角色唯一标识 主键
parent_guidchar(36)父级菜单唯一标识
namevarchar(100)url地址
titlevarchar(100)菜单名称
iconvarchar(100)图标
is_authtinyint(2)是否鉴权
is_linktinyint(2)是否鉴权 1是0否
statustinyint(2)状态
sortint(4)排序
create_timedatetime(3)创建时间
update_timedatetime(3)更新时间
DROP TABLE IF EXISTS `rule`;
 CREATE TABLE `rule` (
  `guid` char(36) NOT NULL,
  `parent_guid` char(36) DEFAULT NULL COMMENT '父级菜单唯一标识',
  `name` varchar(100) NOT NULL COMMENT 'url地址',
  `title` varchar(100) NOT NULL COMMENT '菜单名称',
  `icon` varchar(100) DEFAULT NULL COMMENT '图标',
  `is_auth` tinyint(2) NOT NULL DEFAULT '1' COMMENT '是否鉴权 1是0否',
  `is_link` tinyint(2) NOT NULL DEFAULT '0' COMMENT '是否菜单 1是0否(比如api接口路径)',
  `sort` int(4) NOT NULL DEFAULT '255' COMMENT '排序',
  `status` tinyint(1) DEFAULT '1' COMMENT '状态1可用,0不可用',
  `update_time` datetime(3) NOT NULL COMMENT '更新时间',
  `create_time` datetime(3) NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`guid`) USING BTREE,
  UNIQUE KEY `rulename` (`name`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='权限&菜单表';

角色&权限表role_rule

字段类型描述
role_guidchar(36)角色唯一标识
rule_guidchar(36)权限唯一标识
DROP TABLE IF EXISTS `role_rule`;CREATE TABLE `role_rule` (
  `role_guid` char(36) NOT NULL COMMENT '角色唯一标识',
  `rule_guid` char(36) NOT NULL COMMENT '权限唯一标识',
  UNIQUE KEY `uk_role_guid_rule_guid` (`role_guid`,`rule_guid`) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='角色权限关联表';

本文重点讲述如何利用缓存来判断用户权限

请注意Thinkphp5.1.6+之后的版本才支持中间件。
官方中间件文档:阅读 https://www.kancloud.cn/manual/thinkphp5_1/564279

我们使用 thinkphp5的中间件特性来做统一验证,
首先我们在 application/test/middleware 目录中创建 中间件文件 Auth.php文件

namespace app\test\middleware;use app\common\model\Rule;use think\Controller;class Auth extends Controller{
    /**
     * 默认返回资源类型
     * @var \think\Request $request
     * @var mixed $next
     * @var string $name
     * @throws \Exception
     * @return mixed
     */
    public function handle($request, \Closure $next, $name)
    {
        $path      = strtolower($request->controller() . '/' . $request->action());
        $db_rule   = new Rule();
        $role_guid = ''; //todo 实际应用中 可以通过请求中携带access_token 利用JWT验证后 将得到的用户信息(user_guid/role_guid 等等 传入到model中获取 或者用session传递
        if ($db_rule->checkRule($path, $role_guid) === false) {
            return json(['code' => -1, 'message' => '抱歉您没有权限!']);
        }
        return $next($request);
    }}

然后在application\test目录下 新建middleware.php文件.

// 中间件扩展定义文件return [
    'auth'  => app\test\middleware\Auth::class];

##模型Rule中部分代码参考

<?php

namespace app\common\model;use think\Db;use think\Model;class Rule extends Model{
    protected $pk = 'guid';
    protected $exp = 3600 * 24;
    protected $type = [
        'is_link'  => 'integer',
        'is_auth' => 'integer',
        'sort'    => 'integer'
    ];
    /**
     *  验证角色是否有权限
     * @param string $path 当前路径
     * @param string $role_guid 角色标识,没有传role_guid 获取登陆用户的用户组
     * @throws \Exception
     * @return bool
     */
    public function checkRule($path = '', $role_guid = null)
    {
        // 没有传path地址获取当前
        if ($path == '') {
            $request = request();
            $path    = strtolower($request->controller() . '/' . $request->action());
        }
        //只要当前请求路径是白名单中(rule表中is_auth=0)或者该用户已经有权限 则校验通过
        return in_array($path, $this->getNoAuthRule()) || in_array($path, $this->getPermissionByRoleGuid($role_guid));
    }

    /**
     *  获取白名单列表
     * @throws \Exception
     * @return array
     */
    public function getNoAuthRule()
    {
        $db = new Rule();
        //使用cache写法如果存在缓存则不会查询数据库,非常方便
        return $db->cache('rule:no_auth_list', $this->exp)->where('is_auth', 0)->column('name');
    }

    /**
     * 根据角色guid获取权限列表
     * @param string|null $role_guid 角色标识
     * @throws \Exception
     * @return array
     */
    public function getPermissionByRoleGuid($role_guid)
    {
        $cache_key = 'rule:role:' . $role_guid;
        $map       = [
            ['r.status', '=', 1],
            ['r.is_auth', '=', 1],
            ['rr.role_guid', '=', $role_guid]
        ];
        $join      = [['__RULE__ r', 'rr.rule_guid=r.guid']];
        //使用cache写法如果存在缓存则不会查询数据库,非常方便
        return  Db::name('role_rule')->alias('rr')->join($join)->where($map)->cache($cache_key, $this->exp)->column('r.name');
    }}

复制


阅读 143
全部留言