目录

SpringSecurity权限管理系统实战—一、项目简介和开发环境准备

SpringSecurity权限管理系统实战—二、日志、接口文档等实现

SpringSecurity权限管理系统实战—三、主要页面及接口实现

SpringSecurity权限管理系统实战—四、整合SpringSecurity(上)

SpringSecurity权限管理系统实战—五、整合SpringSecurity(下)

SpringSecurity权限管理系统实战—六、SpringSecurity整合jwt

SpringSecurity权限管理系统实战—七、处理一些问题

SpringSecurity权限管理系统实战—八、AOP 记录用户日志、异常日志

SpringSecurity权限管理系统实战—九、数据权限的配置

前言

这一章的部分是我写到现在最累的一部分,累就累在逻辑的处理上,因为涉及到很多多表的操作,幸好数据库没有设计外键,不然更加恶心。

也让我发现了数据库设计之初的一些命名问题(之后再解决这个问题)。

就像是用户表中的id最好还是用user_id,而我之前用的却是id。这会导致什么问题呢?比如说你在role_user这张关联表中存的肯定是user_id吧,那么你在关联这两个表写sql语句是就要不停的转换id和user_id,脑壳子都给你绕晕了。血淋淋的教训,大家要注意了。

这篇文章只是给一个思路,内容和逻辑都太复杂,还要对原有的部分进行修改,不能再像之前那样一步一步贴代码了

希望各位小伙伴能够多多star支持,您的点赞就是我维护的动力

giteegithub中同步更新源码

附:阿里巴巴数据库设计规范

一、什么是数据权限

权限设计具体来说可以分为功能权限和数据权限。功能权限就是角色能操作哪些接口,而数据权限就是角色能够获取到的哪些数据。

形象点来说,如果现在有一个公司,公司上下有很多部门,部门里有很多员工,而数据权限就是为了让某个部门的人只能获取到自己部门或着是指定部门的员工信息。

二、新建如下表







分别是岗位表,部门表,用户岗位关联表和角色部门关联表

my_user表中添加dept_id字段。my_role表中添加data_scpoe字段。前一个很好理解,就是部门的id,后一个代表的就是角色的数据权限范围

(这篇文章很难写,文章所代表的代码内容也很难写,大家想要理解透彻还是要从源码里看,自己做一遍才能真正的理解)

三、效果

效果

效果就是这样,代码也不贴了,这部分逻辑有点复杂,代码量很大,可以自行去源码中查看。

四、实现

这里只是介绍下如何实现数据权限,参考了若依项目中的实现方法

首先我们自定义一个注解

/**
* 数据权限过滤注解
* @author codermy
* @createTime 2020/8/22
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataPermission {
/**
* 部门表的别名
*/
public String deptAlias() default ""; /**
* 用户表的别名
*/
public String userAlias() default "";
}

再定义一个切面类

	/**
* 数据过滤处理
* @author codermy
* @createTime 2020/8/22
*/
@Aspect
@Component
public class DataScopeAspect { @Autowired
public RoleUserService roleUserService;
/**
* 全部数据权限
*/
public static final String DATA_SCOPE_ALL = "1"; /**
* 自定数据权限
*/
public static final String DATA_SCOPE_CUSTOM = "2"; /**
* 部门数据权限
*/
public static final String DATA_SCOPE_DEPT = "3"; /**
* 部门及以下数据权限
*/
public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; /**
* 仅本人数据权限
*/
public static final String DATA_SCOPE_SELF = "5"; /**
* 数据权限过滤关键字
*/
public static final String DATA_SCOPE = "dataScope"; /**
* 配置织入点
*/
@Pointcut("@annotation(com.codermy.myspringsecurityplus.admin.annotation.DataPermission)")
public void dataScopePointCut()
{
} @Before("dataScopePointCut()")
public void doBefore(JoinPoint point) throws Throwable
{
handleDataScope(point);
} protected void handleDataScope(final JoinPoint joinPoint)
{
// 获得注解
DataPermission controllerDataScope = getAnnotationLog(joinPoint);
if (controllerDataScope == null)
{
return;
}
// 获取当前的用户
JwtUserDto currentUser = SecurityUtils.getCurrentUser();
if (currentUser != null)
{
// 如果是超级管理员,则不过滤数据
if (!currentUser.isAdmin())
{
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
controllerDataScope.userAlias());
}
}
} /**
* 数据范围过滤
*
* @param joinPoint 切点
* @param user 用户
* @param deptAlias 部门别名
* @param userAlias 用户别名
*/
public static void dataScopeFilter(JoinPoint joinPoint, JwtUserDto user, String deptAlias, String userAlias)
{
StringBuilder sqlString = new StringBuilder(); for (MyRole role : user.getRoleInfo())
{
String dataScope = role.getDataScope();
if (DATA_SCOPE_ALL.equals(dataScope))
{
sqlString = new StringBuilder();
break;
}
else if (DATA_SCOPE_CUSTOM.equals(dataScope))
{
sqlString.append(StrUtil.format(
" OR {}.id IN ( SELECT dept_id FROM my_role_dept WHERE role_id = {} ) ", deptAlias,
role.getId()));
}
else if (DATA_SCOPE_DEPT.equals(dataScope))
{
sqlString.append(StrUtil.format(" OR {}.id = {} ", deptAlias, user.getMyUser().getDeptId()));
}
else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
{
sqlString.append(StrUtil.format(
" OR {}.id IN ( SELECT id FROM my_dept WHERE id = {} or find_in_set( {} , ancestors ) )",
deptAlias, user.getMyUser().getDeptId(), user.getMyUser().getDeptId()));
}
else if (DATA_SCOPE_SELF.equals(dataScope))
{
if (StrUtil.isNotBlank(userAlias))
{
sqlString.append(StrUtil.format(" OR {}.id = {} ", userAlias, user.getMyUser().getId()));
}
else
{
// 数据权限为仅本人且没有userAlias别名不查询任何数据
sqlString.append(" OR 1=0 ");
} }
}
if (StrUtil.isNotBlank(sqlString.toString()))
{
BaseEntity baseEntity;
for (int i = 0;i < joinPoint.getArgs().length ;i++ ){
if (joinPoint.getArgs()[i] instanceof BaseEntity){
baseEntity= (BaseEntity) joinPoint.getArgs()[i];
baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
}
} }
} /**
* 是否存在注解,如果存在就获取
*/
private DataPermission getAnnotationLog(JoinPoint joinPoint)
{
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod(); if (method != null)
{
return method.getAnnotation(DataPermission.class);
}
return null;
}
}

解释一下这个切面类的作用就是:

当你在ServiceImpl的某个方法上定义了这个注解时,它就会获取当前登录用户的角色的dataScope(就是数据范围),然后比较它的值,将相应的sql语句存入baseEntity的params中

然后我们只需要在对于需要配置数据权限的mapper.xml中添加${params.dataScope}



再在调用此方法的service方法上添加注解@DataPermission(deptAlias = "d", userAlias = "u")

即可



这里我在BaseEntity中添加了一个params属性来用于存放数据权限的sql



这样当我们需要调用这个sql时,如果未过滤权限时,sql是这样的

SELECT u.id, u.dept_id, u.user_name, u.password, u.nick_name
, u.phone, u.email, u.status, u.create_time, u.update_time
FROM my_user u
LEFT JOIN my_dept d ON u.dept_id = d.id
WHERE u.dept_id = ?
OR u.dept_id IN (
SELECT e.id
FROM my_dept e
WHERE FIND_IN_SET(?, ancestors)
)
ORDER BY u.id

如果我们给这个角色的数据权限种类是自定数据权限,sql就会是下面这样

SELECT u.id, u.dept_id, u.user_name, u.password, u.nick_name
, u.phone, u.email, u.status, u.create_time, u.update_time
FROM my_user u
LEFT JOIN my_dept d ON u.dept_id = d.id
WHERE (u.dept_id = ?
OR u.dept_id IN (
SELECT e.id
FROM my_dept e
WHERE FIND_IN_SET(?, ancestors)
))
AND d.id IN (
SELECT dept_id
FROM my_role_dept
WHERE role_id = 2
)
ORDER BY u.id

那么如果我们给角色 ‘普通用户’如下数据权限



那么当我们登录该角色的用户时,便只能访问到相应部门下的用户信息。





当我们再在部门的相应方法和sql上再添加上注解时过滤语句时,那么效果就是这样的



giteegithub中同步更新源码

SpringSecurity权限管理系统实战—九、数据权限的配置的更多相关文章

  1. SpringSecurity权限管理系统实战—一、项目简介和开发环境准备

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  2. SpringSecurity权限管理系统实战—二、日志、接口文档等实现

    系列目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战 ...

  3. SpringSecurity权限管理系统实战—四、整合SpringSecurity(上)

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  4. SpringSecurity权限管理系统实战—六、SpringSecurity整合jwt

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  5. SpringSecurity权限管理系统实战—七、处理一些问题

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  6. SpringSecurity权限管理系统实战—八、AOP 记录用户、异常日志

    目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...

  7. SpringSecurity权限管理系统实战—五、整合SpringSecurity(下)

    系列目录 前言 上篇文章SpringSecurity整合了一半,这次把另一半整完,所以本篇的序号接着上一篇. 七.自定义用户信息 前面我们登录都是用的指定的用户名和密码或者是springsecurit ...

  8. Smartbi权限安全管理系统_保障数据权限安全

    思迈特软件Smartbi具有完善的安全管理体系,Smartbi权限安全管理系统它可以控制用户功能权限.数据访问权限.资源访问权限.Smartbi权限安全管理系统支持按用户.用户组.角色进行管理:支持多 ...

  9. 08 SSM整合案例(企业权限管理系统):08.权限控制

    04.AdminLTE的基本介绍 05.SSM整合案例的基本介绍 06.产品操作 07.订单操作 08.权限控制 09.用户操作 10.权限关联与控制 11.AOP日志 08.权限控制 SSM权限操作 ...

随机推荐

  1. Laravel 配置 SqlDebug 服务,进行实时监听打印 SQL

    0:释义 什么是服务容器 简而言之,Laravel 服务容器 是一个用于存储绑定组件的盒子,它还会为应用提供所需的服务. Laravel 服务容器是用于管理类的依赖和执行依赖注入的工具,By Lara ...

  2. PHP pclose() 函数

    定义和用法 pclose() 函数关闭由 popen() 打开的进程. 如果失败,该函数返回 FALSE. 语法 pclose(pipe) 参数 描述 pipe 必需.规定由 popen() 打开的进 ...

  3. 2020牛客暑假多校训练营 第二场 E Exclusive OR FWT

    LINK:Exclusive OR 没做出 原因前面几篇说过了. 根据线性基的知识容易推出 不超过\(w=log Mx\)个数字即可拼出最大值 其中Mx为值域. 那么考虑w+2个数字显然也为最大值.. ...

  4. Python机器学习及实践_从零开始通往KAGGLE竞赛之路PDF高清完整版免费下载|百度云盘|Python基础教程免费电子书

    点击获取提取码:i5nw Python机器学习及实践面向所有对机器学习与数据挖掘的实践及竞赛感兴趣的读者,从零开始,以Python编程语言为基础,在不涉及大量数学模型与复杂编程知识的前提下,逐步带领读 ...

  5. Spring Boot的自动配置,到底是怎么做到?

    作者:祖大帅 链接:juejin.im/post/5b679fbc5188251aad213110 来源:掘金 1. Spring Boot.Spring MVC 和 Spring 有什么区别? 分开 ...

  6. kubernetes 中安装 heapster 问题

    step1: 在官网下载部署文件 https://github.com/kubernetes-retired/heapster/tree/master/deploy/kube-config/influ ...

  7. Python精选库大全,建议收藏留用!

    Python为啥这么火,这么多人学,就是因为简单好学,功能强大,整个社区非常活跃,资料很多.而且这语言涉及了方方面面,比如自动化测试,运维,爬虫,数据分析,机器学习,金融领域,后端开发,云计算,游戏开 ...

  8. C语言学习笔记之进制之间的转换

    这一篇主要是对进制之间转换的讲解,方便查看,以防忘记 二进制      逢二进一 八进制      逢八进一                以0开头, 0就是8进制的标志 十进制      逢十进一 ...

  9. SSM框架整合Demo

    目前项目大都开始采用SSM结构进行搭建,因为涉及项目比较多,新来的需求都是从现有项目中迁移一份出来进行修改,有的时候两个项目差别还是比较大,并不完全需要原有项目的东西,进行删减也是一项费神费时的事情, ...

  10. 商品描述(动画)--- jQuery

    本文章实现是基于jQuery展示商品描述的一个功能 (1)鼠标移入显示描述内容,鼠标移开内容隐藏.先来看看一个先后效果. (2)jQuery所以的文件可以自行下载,也可以在我主页找到文件,右键文件名复 ...