您现在的位置是:门户> web开发> ThinkPHP

【权限&缓存】角色权限设计以及利用缓存判断权限
x0ffer 2018-12-04 202人围观 0条评论
简介

    对于后台管理系统,权限管理是最基本的一共功能, 一般会涉及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');
        }}

    复制


分享:

文章评论