在之前我们已经了解了 think3.2Rbac 的权限管理操作,但是在 thinkPHP5 中 thinkPHP 没有内置 Rabc 操作,所以我们需要使用一个 thinkPHP 的 Rbac 拓展来实现权限管理,在 thinkPHP 中我们可以使用 gmars/tp5-rbac 拓展来实现权限管理
gmars/tp5-rbac 地址:https://packagist.org/package…
一:gmars/tp5-rbac 安装
composer require gmars/tp5-rbac
二:gmars/tp5-rbac 使用
1:Rbac 数据库创建
在 gmars/tp5-rbac 中我们需要使用到六张表,分别为:权限节点表 (permission),permission_category(权限分组表),role(角色表),role_permission(角色权限关联表),user(用户表),user_role(用户角色关联表)
当我们使用 composer 将 gmars/tp5-rbac 下载下来之后,我们可以发现在 vendorgmarstp5-rbac 目录下有一个 gmars_rbac.sql 文件,此文件内就为我们所需要创建表的 sql
下面 sql 中 ### 为你的表前缀,下面只是展示我们呢所需要的表 sql,创建表 gmars/tp5-rbac 提供了方法来帮我们自动创建我们所需要的表
// 实例化 rbac
$rbac = new Rbac();
// 初始化 rbac 所需的表,可传入参数 $db 为数据库配置项默认为空则为默认数据库 (考虑到多库的情形)
$rbac->createTable();
上面的方法会生成 rbac 所需要的表,一般只执行一次,为了安全,执行后会加锁,下次要执行需要删除锁文件再执行
(1):权限节点表 (permission)
DROP TABLE IF EXISTS `###permission`;
CREATE TABLE `###permission` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT ''COMMENT' 权限节点名称 ',
`type` smallint(4) unsigned NOT NULL DEFAULT '0' COMMENT '权限类型 1api 权限 2 前路由权限',
`category_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '权限分组 id',
`path` varchar(100) NOT NULL DEFAULT ''COMMENT' 权限路径 ',
`path_id` varchar(100) NOT NULL DEFAULT ''COMMENT' 路径唯一编码 ',
`description` varchar(200) NOT NULL DEFAULT ''COMMENT' 描述信息 ',
`status` smallint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态 0 未启用 1 正常',
`create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_permission` (`path_id`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限节点表';
(2):permission_category(权限分组表
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS `###permission_category`;
CREATE TABLE `###permission_category` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ''COMMENT' 权限分组名称 ',
`description` varchar(200) COLLATE utf8mb4_general_ci NOT NULL DEFAULT ''COMMENT' 权限分组描述 ',
`status` smallint(4) unsigned NOT NULL DEFAULT '1' COMMENT '权限分组状态 1 有效 2 无效',
`create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '权限分组创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT '权限分组表';
(3):role(角色表)
DROP TABLE IF EXISTS `###role`;
CREATE TABLE `###role` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT ''COMMENT' 角色名 ',
`description` varchar(200) NOT NULL DEFAULT ''COMMENT' 角色描述 ',
`status` smallint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态 1 正常 0 未启用',
`sort_num` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '排序值',
PRIMARY KEY (`id`),
KEY `idx_role` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
(4):role_permission(角色权限关联表)
DROP TABLE IF EXISTS `###role_permission`;
CREATE TABLE `###role_permission` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`role_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '角色编号',
`permission_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '权限编号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色权限对应表';
(5):user(用户表)
DROP TABLE IF EXISTS `###user`;
CREATE TABLE `###user` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_name` varchar(50) NOT NULL DEFAULT ''COMMENT' 用户名 ',
`password` varchar(64) NOT NULL DEFAULT ''COMMENT' 用户密码 ',
`mobile` varchar(20) NOT NULL DEFAULT ''COMMENT' 手机号码 ',
`last_login_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最后一次登录时间',
`status` smallint(4) unsigned NOT NULL DEFAULT '0' COMMENT '状态 0 禁用 1 正常',
`create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '账号创建时间',
`update_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '信息更新时间',
PRIMARY KEY (`id`),
KEY `idx_user` (`user_name`,`mobile`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
(6):user_role(用户角色关联表)
DROP TABLE IF EXISTS `###user_role`;
CREATE TABLE `###user_role` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '用户 id',
`role_id` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '角色 id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户角色对应关系';
2:rbac 的相关操作
(1) 创建权限分组
// 实例化 rbac
$rbac = new Rbac();
// 创建权限分组
$rbac->savePermissionCategory([
'name' => '用户管理组',
'description' => '网站用户的管理',
'status' => 1
]);
当 savePermissionCategory 方法中包含了主键 id 时为编辑权限分组
(2) 创建权限节点
// 实例化 rbac
$rbac = new Rbac();
// 创建权限节点
$rbac->createPermission([
'name' => '文章列表查询',
'description' => '文章列表查询',
'status' => 1,
'type' => 1,//type 为权限类型 1 为后端权限 2 为前端权限
'category_id' => 1,// 权限分组的 id
'path' => 'article/content/list',
]);
当 createPermission 方法中包含了主键 id 时为编辑权限节点
(3) 创建角色 & 给角色分配权限
// 实例化 rbac
$rbac = new Rbac();
// 创建角色 & 给角色分配权限
$rbac->createRole([
'name' => '内容管理员',
'description' => '负责网站内容管理',
'status' => 1
], '1,2,3');
当 createRole 方法的第一个参数中包含了主键 id 时为编辑角色, 第二个参数为权限节点的 id 拼接的字符串
(4) 给用户分配角色
// 实例化 rbac
$rbac = new Rbac();
// 给用户分配角色
$rbac->assignUserRole(1, [1]);
第一个参数为用户 id, 第二个参数为角色 id 的数组, 此方法会先删除用户之前分配的角色,然后重新给用户分配角色
(5) 获取权限分组列表
// 实例化 rbac
$rbac = new Rbac();
// 获取权限分组列表
$rbac->getPermissionCategory([['status', '=', 1]]);// 参数为权限分组表的条件
(6) 获取权限列表
// 实例化 rbac
$rbac = new Rbac();
// 获取权限列表
$rbac->getPermission([['status', '=', 1]]);// 参数为权限表条件
(7) 获取角色列表
// 实例化 rbac
$rbac = new Rbac();
// 获取角色列表
$rbac->getRole([], true);
第一个参数为 role 表的条件,第二个参数为 true 时查询角色分配的所有权限 id
(8) 删除权限相关方法
删除权限分组
$rbac->delPermissionCategory([1,2,3,4]);
删除权限
$rbac->delPermission([1,2,3,4]);
删除角色
$rbac->delRole([1,2,3,4]);
(9) 权限验证
[1]service 方式
service 方式因为要用到 session 一般要依赖于 cookie, 在用户登录后获取用户权限并将用户权限进行缓存
$rbac->cachePermission(1);// 参数为登录用户的 user_id,返回值为用户权限列表
验证,判断用户对于指定的节点是否具有权限:
$rbac->can('article/channel/list');
[2]jwt 方式
jwt 方式在前后端分离结构用的比较普遍。在用户登录后需要获取 token,将下面方法获取到的 token 传递到前端
$rbac->generateToken(1);// 第一个参数为登录的用户 id,第二个参数为 token 有效期默认为 7200 秒,第三个参数为 token 前缀 返回结果为
返回值示例如下:
array(3) {["token"] => string(32) "4c56b80f06d3d8810b97db33a1291694"
["refresh_token"] => string(32) "17914241bde6bfc46b20e643b2c58279"
["expire"] => int(7200)
}
使用 refresh_token 刷新权限, 有效期内使用 refresh_token 来刷新授权
$rbac->refreshToken('17914241bde6bfc46b20e643b2c58279');
验证,前端将 token 传递到后端,后端校验用户是否具有指定节点权限
$rbac->can('article/channel/list');