一、数据权限设计初衷
近期在做数据中台的项目,主要包括元数据管理,质量规则,数据服务,数据导出等多个业务模块,目前该中台只是供内部使用,但随着业务的正式上线,必然会在公网进行访问。因此,如何控制每个用户只能访问自己能够看到的数据内容至关重要,这就存在用户数据权限的设计问题。
二、前提条件
(1)满足不同的业务授权方式统一化,通用且方便扩展;
(2)与业务模块完全解耦,减少代码的侵入,提高权限系统的复用性;
(3)业务方不需要关心授权流程及授权资源回显问题。要保证不同的资源类型,在授权时,能够自动从后台获取需要授权的资源列表信息进行授权。
(4)授权系统易用,可维护性高。
三、数据权限设计整体架构

本次设计是基于用户-角色-资源体系构建的通用数据权限系统。通过将角色与资源绑定,再将用户和角色绑定,从而达到用户与资源的关联关系。
在资源模块中,提供统一资源授权接口和统一资源鉴权接口。统一资源授权接口主要是用来提供不同资源在授权时web页面回显的问题,后台主要是通过反射的方式来实现的。统一资源鉴权接口主要是提供gaia用户的鉴权操作,通过对用户所拥有的资源类型和角色的判断,从而给中台返回该用户能够访问的资源id集合,中台返回具体的资源内容信息。
四、数据权限核心代码实现
4.1依赖springboot对bean的管理,达到接口实现的自动扫描操作。

public abstract class ClassUtil<T> implements InitializingBean, ApplicationContextAware {protected ApplicationContext applicationContext;private final Map<String, T> map = new HashMap<>();/*** 设置spring上下文* @param applicationContext spring上下文*/@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}@Overridepublic void afterPropertiesSet() throws Exception {setImplementedBeanMap(map, Objects.nonNull(getTypeClass()) ? getTypeClass() : getTClass());}/*** 设置接口实现类Map* @param map 存放接口实现类Map* @param type 接口类*/protected <E> void setImplementedBeanMap(Map<String, E> map, Class<E> type) {Map<String, E> beanMap = applicationContext.getBeansOfType(type);for (E storageType : beanMap.values()) {map.put(storageType.getClass().getSimpleName(), storageType);}}/*** 获取实现类集合*/protected Map<String, T> getUseMap() {return map;}@SuppressWarnings("unchecked")private Class<T> getTClass() {return (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];}/*** 获取接口类Class*/protected abstract Class<T> getTypeClass();}

4.2 统一授权接口实现类

public interface PrivilegeResourceTemplate {Pagination<PrivilegeResourceEntity> showResourceList(String className, String keyword,  Integer pageNum, Integer pageSize);
}

前端调用统一接口

@Service
public class PrivilegeBaseServiceImpl extends ClassUtil<PrivilegeResourceTemplate> implements PrivilegeBaseService {@Overrideprotected Class<PrivilegeResourceTemplate> getTypeClass() {return PrivilegeResourceTemplate.class;}/*** 授权资源列表*   统一授权资源展示接口* @param className 具体实现类* @param keyword   关键字* @param pageNum   分页参数* @param pageSize  分页参数* @return*/@Overridepublic Pagination<PrivilegeResourceEntity> resourceLists(String className, String keyword, Integer pageNum, Integer pageSize) {Map<String, PrivilegeResourceTemplate> map = getUseMap();return map.get(className).showResourceList(className, keyword, pageNum, pageSize);}/*** 获取实现类列表*   通过该方法,可以获取接口的具体实现类有哪些* @return*/@Overridepublic Set<String> getClassImpl() {Map<String, PrivilegeResourceTemplate> map = getUseMap();Set<String> classImpls = map.keySet();return classImpls;}}

4.3统一鉴权接口,用到了redis,如果不需要,可以去掉。

public interface PrivilegeCommonAuthorize {List<Object> getUserRefResourceIds(String resourceType);}
@Service
public class PrivilegeCommonAuthorizeImpl implements PrivilegeCommonAuthorize {@Autowiredprivate RedisUtil redisUtil;@Autowiredprivate PrivilegeRoleRefUserMapper privilegeRoleRefUserMapper;@Overridepublic List<Object> getUserRefResourceIds(String resourceType) {if (StringUtils.isEmpty(resourceType)) {return null;}String employeeNo = "涉及业务,已去掉,有需要自己添加逻辑";String key = CommonConstants.USER_KEY + employeeNo;Set<Object> roleIds = redisUtil.sGet(key);/*** 如果redis中没有,则去数据库查询,并存入redis*/if (roleIds.isEmpty()) {roleIds = privilegeRoleRefUserMapper.queryRoleRefUserByUserId(employeeNo);}if (!roleIds.isEmpty()) {redisUtil.sSet(key, roleIds.toArray());} else {throw new CustomException("该用户未被授权,请先授权后再进行操作");}Set<String> roleIdsSet = new HashSet<>();roleIds.forEach(roleId -> {String str = resourceType + CommonConstants.SPLITOR + roleId;String roleKey = CommonConstants.ROLE_KEY + Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8));roleIdsSet.add(roleKey);});return redisUtil.multiGet(roleIdsSet);}
}

五、数据权限实现流程
新增资源时的配置页面:

5.1 开发人员在开发完成之后,需要在该页面配置资源类型和该资源的具体实现类(后台实现PrivilegeResourceTemplate 接口的具体实现类)。
5.2 在授权时,前端选择资源类型,后台接收到资源类型的值,从数据库查询该资源类型具体的实现类,然后通过反射,获取该资源类型的授权资源内容回显在web页面进行授权。
5.3 鉴权时,用户登录中台,通过网关获取到用户的信息,然后从redis(mysql)中查询该用户(对应的资源类型所拥有)的角色信息,然后通过角色信息,查询该角色下挂载的资源内容(资源id),返回给中台具体接口进行回显拦截,从而达到权限控制的目的。
六、数据库表结构设计
1、用户表

CREATE TABLE `privilege_user` (`privilege_user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`user_name` varchar(16) DEFAULT NULL COMMENT '用户名',`employ_id` varchar(10) DEFAULT NULL COMMENT '员工编码',`account` varchar(12) DEFAULT NULL COMMENT 'gaia账号',`business_descr` varchar(32) DEFAULT NULL COMMENT '所属公司',`creator` varchar(16) DEFAULT NULL COMMENT '创建人姓名',`user_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '用户状态,0标识正常,1表示关闭',`create_time` datetime DEFAULT NULL,PRIMARY KEY (`privilege_user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4

2、角色表

CREATE TABLE `privilege_role` (`privilege_role_id` varchar(18) NOT NULL COMMENT '主键,角色id',`role_name` varchar(32) DEFAULT NULL COMMENT '角色名',`role_descr` varchar(256) DEFAULT NULL COMMENT '角色描述',`added_by_name` varchar(16) DEFAULT NULL COMMENT '创建人姓名',`role_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '角色状态,0表示正常,1表示关闭',`create_time` datetime DEFAULT NULL,PRIMARY KEY (`privilege_role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

3、角色用户关联表

CREATE TABLE `privilege_role_ref_user` (`privilege_role_ref_user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`role_id` varchar(18) DEFAULT NULL COMMENT '角色id',`user_id` varchar(10) DEFAULT NULL COMMENT '用户id',`create_time` datetime DEFAULT NULL,`update_time` datetime DEFAULT NULL,PRIMARY KEY (`privilege_role_ref_user_id`),KEY `index_name` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4

4、角色和资源关联表

CREATE TABLE `privilege_role_ref_resource` (`privilege_role_ref_resource_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',`role_id` varchar(18) DEFAULT NULL COMMENT '角色id',`resource_id` bigint(20) DEFAULT NULL COMMENT '资源模型id',`resource_type` varchar(32) DEFAULT NULL COMMENT '资源类型',`create_time` datetime DEFAULT NULL,PRIMARY KEY (`privilege_role_ref_resource_id`),KEY `index_name` (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4

5、资源配置表

CREATE TABLE `privilege_resource_class` (`resource_reflex_id` bigint(20) NOT NULL AUTO_INCREMENT,`resource_type` varchar(32) DEFAULT NULL COMMENT '资源类型',`resource_name` varchar(255) DEFAULT NULL COMMENT '资源名',`class_name` varchar(128) DEFAULT NULL COMMENT '类名',`creator` varchar(16) DEFAULT NULL COMMENT '创建人',`create_time` datetime DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`resource_reflex_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4

七、总结
1、该数据权限设计系统,完全解耦业务代码,通用性强,可扩展。
2、表结构清晰,模块明朗,容易维护;
3、设计简单,方便使用。

通用数据权限设计方案相关推荐

  1. java 数据权限_通用数据权限的思考与设计

    1.数据权限概述 1.1.什么是数据权限? 如果想学习Java工程化.高性能及分布式.深入浅出.微服务.Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:7877071 ...

  2. B/S页面通用数据权限控制[转]

    数据权限常见场景有: 数据仅部门级可见 数据仅本人可见 数据仅某角色可见 在可见的基础上,进行功能控制: 修改,删除 在树形结构里,在可见基础上进行 新增/修改/删除控制 我的实现方式: 资源---所 ...

  3. 复杂数据权限设计方案

    需求:有个权限树,资源挂在树的节点上面.父节点的权限可以访问所有子节点的资源. 更具体点,一个公司有一个部门,这个部门是棵树(权限树).每发布一个课程,都需要设置属于哪个部门的权限.每个人属于部门.这 ...

  4. java(springboot) mybatis 数据权限详细实现(图文)

    噼里啪啦 来吧,整起,又一新功能,通用数据权限,注意是通用,通用的东西,反正挺烦的,(每天喝点茶,刷点文章,发表下博文,改下bug,写点crud多舒服的,啊哈哈,噗) 我还是第一次搞这玩意儿,因为之前 ...

  5. 通用权限管理设计 之 数据权限

    阅读目录 前言 初步分析 通用查询机制 数据权限规则 实际应用 结语 前言 前一篇文章<通用权限管理设计 之 数据库设计方案>介绍了[主体]- [领域] - [权限]( who.what. ...

  6. (转)通用权限管理设计 之 数据权限

    转自:leo's Space http://www.cnblogs.com/leoxie2011/archive/2012/03/20/2408542.html 阅读目录 前言 初步分析 通用查询机制 ...

  7. 通用数据级别权限的框架设计与实现(4)-单条记录的权限控制

    查看上篇文章通用数据级别权限的框架设计与实现(3)-数据列表的权限过滤,我们开始在原来的基础上实现单条权记录的权限控制. 相信前面的列表权限控制,很多系统都可以做到,但如何在上面列表的权限过滤中实现通 ...

  8. 通用数据级别权限的框架设计与实现(3)-数据列表的权限过滤

    查看上篇文章通用数据级别权限的框架设计与实现(2)-数据权限的准备工作,我们开始数据列表的权限过滤. 原理:我们在做过滤列表时,根据用户权限自动注入到相关SQL中,实现相关过滤,如果拥有全部权限,则不 ...

  9. 天鸟技术中台-建设过程-日常经验2:通用参数和数据权限控制

    技术中台,服务于 无数个 独立的项目. 每个项目,单独对应1个App和appId. 查询和创建等接口,必须提供appId,区分是哪个app的数据. 而技术中台的平台管理端,是管理所有的数据,appId ...

  10. web系统权限之数据权限

    2019独角兽企业重金招聘Python工程师标准>>> 转载地址:http://www.cnblogs.com/leoxie2011/archive/2012/03/20/24085 ...

最新文章

  1. 关于安卓录屏的权限问题
  2. HDU 1513 Palindrome(最长公共子序列)
  3. 爬虫好学吗python-小白python学到什么程度可以学习网络爬虫? ?
  4. WordPress的option处理 - 底层数据库表的操作
  5. Flash基本工具练习
  6. 归纳推理测试没做完_朋友买了1斤紫菜,2年还没吃完,我教他这样做,2个月就吃完了...
  7. 专业软件 —— 硬件评测
  8. Javascript取select的选中值和文本
  9. LeetCode 1381. 设计一个支持增量操作的栈(deque/数组)
  10. 吴恩达《机器学习》学习笔记五——逻辑回归
  11. CSDN博客如何调整文字的字体、大小、颜色
  12. 读凤凰网经典语句记录一
  13. 风变编程python第一关_风变编程python学习心得
  14. hadoop提交作业到云端问题解决
  15. 使用xshell连接腾讯云服务器
  16. ODM操作MongoDB
  17. Delphi著名皮肤控件库大全
  18. 【ZT】【详细教程】WPS如何关闭自动更新和WPS热点?(ksomisc.exe)
  19. MySQL - 5.7.31 - winx64 安装教程
  20. 笔记本重装系统如何找回之前自己自带的office

热门文章

  1. matlab调用pspice结果,使PSpice输出数据文件可以导入到MATLAB中绘制图形.pdf
  2. 关于影视后期制作的就业市场调查报告
  3. [整理]VS2010中文版配置opencv2.4.8
  4. GPIO 模拟SPI
  5. Win8操作系统下IIS如何配置asp.net的运行环境
  6. 空间解析几何之向量运算
  7. ShadowGun Billboard Blinking God Rays
  8. linux生成手机号码字典,字典生成器,木头超级字典生成器
  9. 联想服务器加装显卡无显示,标配11201355主板的启天M4330在 Win8系统加装独立显卡“无显无报警”...
  10. linux多级菜单脚本教程,Linux下使用readline库编程实现多级CLI菜单