数据权限限定办法

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 100412
 Source Host           : localhost:22066
 Source Schema         : base_db

 Target Server Type    : MySQL
 Target Server Version : 100412
 File Encoding         : 65001

 Date: 15/03/2020 11:28:38
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_base_person_role
-- ----------------------------
DROP TABLE IF EXISTS `t_base_person_role`;
CREATE TABLE `t_base_person_role`  (
  `person_role_id` int(11) NOT NULL COMMENT '主键ID',
  `identity_id` int(11) NOT NULL COMMENT '身份ID',
  `person_id` int(11) NOT NULL COMMENT '人员ID',
  `role_id` int(11) NOT NULL COMMENT '角色ID',
  `business_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '哪个省?哪个市?哪个县?哪个单位?哪个子单位?',
  `update_ts` datetime(0) NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间戳',
  PRIMARY KEY (`person_role_id`) USING BTREE,
  UNIQUE INDEX `identity_id`(`identity_id`, `person_id`, `role_id`, `business_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_base_person_role
-- ----------------------------

-- ----------------------------
-- Table structure for t_base_resource
-- ----------------------------
DROP TABLE IF EXISTS `t_base_resource`;
CREATE TABLE `t_base_resource`  (
  `resource_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `resource_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源名称',
  `resource_code` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '资源代码',
  `resource_sql` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '查找对应单位的SQL',
  `update_ts` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '最后更新时间戳',
  PRIMARY KEY (`resource_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_base_resource
-- ----------------------------
INSERT INTO `t_base_resource` VALUES (1, '单位', 'bureau_id', 'select ? as bureau_id', '2020-03-15 11:27:48');
INSERT INTO `t_base_resource` VALUES (2, '学校', 'school_id', 'select ? as bureau_id', '2020-03-15 11:28:08');
INSERT INTO `t_base_resource` VALUES (3, '班级', 'class_id', 'select bureau_id from t_base_class where class_id=?', '2020-03-15 11:14:39');
INSERT INTO `t_base_resource` VALUES (4, '部门', 'org_id', 'select bureau_id from t_base_organization where org_id=?', '2020-03-15 11:19:47');
INSERT INTO `t_base_resource` VALUES (5, '教职工', 'teacher_id', 'select bureau_id from t_base_teacher where teacher_id=?', '2020-03-15 11:23:02');
INSERT INTO `t_base_resource` VALUES (6, '学生', 'student_id', 'select bureau_id from t_base_student where student_id=?', '2020-03-15 11:20:34');
INSERT INTO `t_base_resource` VALUES (7, '家长', 'parent_id', 'select bureau_id from t_base_parent where parent_id=?', '2020-03-15 11:20:53');

-- ----------------------------
-- Table structure for t_base_role
-- ----------------------------
DROP TABLE IF EXISTS `t_base_role`;
CREATE TABLE `t_base_role`  (
  `role_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称',
  `distribute_able` int(255) NOT NULL DEFAULT 1 COMMENT '是否可以分配给真实的人员',
  `update_ts` datetime(0) NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间戳',
  PRIMARY KEY (`role_id`) USING BTREE,
  INDEX `distribute_able`(`distribute_able`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '(1)此角色表是基础数据内置的角色表,不是为共享给其它系统的公用概念,与分管工作有本质的区别。
(2)有指定角色的人员,不管是真实的人员,还是系统虚拟的管理人员,都需要在指定角色时配置数据范围,即哪个市,哪个校,哪个区,哪个单位
(3)系统管理员是不能二次分配给真实人员的。
(4)除系统管理员外,其它管理员角色是不可分配给真实人员的。' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_base_role
-- ----------------------------
INSERT INTO `t_base_role` VALUES (1, '系统管理员', 0, '2020-03-15 10:11:43');
INSERT INTO `t_base_role` VALUES (2, '省管理员', 1, '2020-03-15 10:11:43');
INSERT INTO `t_base_role` VALUES (3, '市管理员', 1, '2020-03-15 10:11:43');
INSERT INTO `t_base_role` VALUES (4, '县区管理员', 1, '2020-03-15 10:11:43');
INSERT INTO `t_base_role` VALUES (5, '单位管理员', 1, '2020-03-15 10:11:43');
INSERT INTO `t_base_role` VALUES (6, '分校(教学点)管理员', 1, '2020-03-15 10:11:43');

-- ----------------------------
-- Table structure for t_sys_identity
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_identity`;
CREATE TABLE `t_sys_identity`  (
  `identity_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '身份ID',
  `identity_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '身份名称',
  `exposed` int(255) NOT NULL DEFAULT 1 COMMENT '其它系统是否可见',
  `update_ts` datetime(0) NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间戳',
  PRIMARY KEY (`identity_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_sys_identity
-- ----------------------------
INSERT INTO `t_sys_identity` VALUES (1, '系统管理员', 0, '2020-03-15 10:13:10');
INSERT INTO `t_sys_identity` VALUES (2, '教职工', 1, '2020-03-15 10:13:10');
INSERT INTO `t_sys_identity` VALUES (3, '学生', 1, '2020-03-15 10:13:10');
INSERT INTO `t_sys_identity` VALUES (4, '家长', 1, '2020-03-15 10:13:10');

-- ----------------------------
-- Table structure for t_sys_loginperson
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_loginperson`;
CREATE TABLE `t_sys_loginperson`  (
  `login_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `login_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '登录名',
  `person_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '姓名',
  `pwd` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
  `salt` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '盐',
  `identity_id` int(11) NOT NULL COMMENT '身份ID',
  `person_id` int(11) NOT NULL COMMENT '人员ID',
  `update_ts` datetime(0) NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '更新时间戳',
  PRIMARY KEY (`login_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_sys_loginperson
-- ----------------------------

SET FOREIGN_KEY_CHECKS = 1;

2、利用swagger的注释进行角色访问权限控制

// PingExample godoc
// @Summary 获取一条数据记录的示例
// @Description 获取一条数据记录的示例
// @Tags 获取一条数据记录的示例
// @Accept json
// @Param id query int true "单条记录的id"
// @Produce json
// @Success 200 {string} string "pong"
// @Router /shortcutkey/SelectSingle [get]
// @X-Role-Resource {"role_id":[1,2,3,4,5],"resource_id":1}

最后这一句是有用的,描述了哪些角色可以使用这个接口,本接口相关的是哪类资源。

3、每次构建前

swag init

4、初始化拦截器检查列表

//读取doc目录下的swagger.json
	f, err := os.Open("./docs/swagger.json")
	if err != nil {
		fmt.Println("读取swagger.json失败!")
		return
	}
	content, _ := ioutil.ReadAll(f)
	var inter interface{}
	err = json.Unmarshal(content, &inter)
	if err != nil {
		fmt.Println("ERROR: ", err.Error())
		return
	}
	var xRoleResource map[string]interface{}
	m := inter.(map[string]interface{})
	n := m["paths"].(map[string]interface{})
	for k,v := range n {
		t:=v.(map[string]interface{})
		if t["get"]!=nil{
			d:=t["get"].(map[string]interface{})
			xRoleResource =d["x-role-resource"].(map[string]interface{})
		}
		if t["post"]!=nil{
			p:=t["post"].(map[string]interface{})
			xRoleResource =p["x-role-resource"].(map[string]interface{})
		}
		fmt.Println("接口地址:"+k)
		fmt.Println("使用的资源ID:"+fmt.Sprintf("%d", int(xRoleResource["resource_id"].(float64))))
		t1:=xRoleResource["role_id"].([]interface{})
		for i := 0; i < len(t1); i++ {
			fmt.Print(int(t1[i].(float64)), "	")
		}
	}

5、在拦截器中进行拦截检查

1、根据cookie中的加密串,解密还原为identity_id和person_id.
2、根据identity_id+person_id查询t_base_person_role,获取到role_id,business_id(可能是省市县,单位,子单位),考虑性能,可以读取一次后保存到缓存中,有TTL值,比如10分钟。
3、根据swagger的解析json,可以知道当前拦截的接口是哪个,需要拦截的resource_id是什么,限定的role_id有哪些。
4、根据统一获取的bureau_id,通过一个通用接口,获取单位的省市县,单位,子单位等一系列值,考虑到性能,可以上基础数据开发人员提供,在维护更新单位时一并删除缓存即可。
5、两组数据进行交叉对比,存在交集表示可以操作,否则是没有权限操作此接口,挡回。

6、总结

(1)此设计对整体系统要有控制权,每一个环节必须按要求开发,比如统一的bureau_id参数。
(2)此设计无通用性,只能是一种思路。
(3)性能上可以通过缓存等方式进行减压,并发也没有关系。
(4) 每个系统,需要有独立的mysql用户帐号,不能都统一用root,基础数据也不能使用root,因为一旦被暴库,可能全面有被删除数据的风险,使用权限低的mysql帐号,可以限定操作权只在自己的数据库内,不会损坏其它系统的数据,这个确实非常重要。

原文地址:https://www.cnblogs.com/littlehb/p/12492302.html