目录

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. Python创建字符串

    Python创建字符串: 一般情况下可以使用 ' 或 " 创建字符串 或 使用引用字符串变量 或 字符串表达式. # 字符串的创建 # 使用 ' 或 “ 进行创建 strs = 'ABCDE ...

  2. PHP curl_strerror函数

    (PHP 5 >= 5.5.0) curl_strerror — 返回错误码的描述. 说明 string curl_strerror ( int $errornum ) 返回错误码的文本描述信息 ...

  3. CF 题目选做

    写省选的题目对noip没什么大用 关键是 细节题或者是思考题比较重要 练思维自然是CF比较好了 把我见到的比较好的CF题放上来刷一刷. LINK:Complete the projects 就是说一个 ...

  4. 分享一个内网穿透工具frp

    首先简单介绍一下内网穿透: 内网穿透:通过公网,访问局域网里的IP地址与端口,这需要将局域网里的电脑端口映射到公网的端口上:这就需要用到反向代理,即在公网服务器上必须运行一个服务程序,然后在局域网中需 ...

  5. 云原生数据库mysql对共享存储分布式文件系统的接口需求分析

    1. 引言 云原生数据库跟分布式mpp数据库是有差异的,虽然两者都是计算与存储分离,但是在资源的占用上有所不同.云原生数据库是shard everything架构,其依赖的存储资源.内存资源.事务资源 ...

  6. RF,SVM和NN的优缺点

    1. 随机森林优缺点 随机森林(RF)是Bagging的一个扩展变体.RF在以决策树为基分类器进行集成的基础上,进一步在决策树的训练过程中引入了随机属性选择. Bagging就是对数据集训练多个基分类 ...

  7. JDK8 String类知识总结

    一.概述 java的String类可以说是日常实用的最多的类,但是大多数时候都只是简单的拼接或者调用API,今天决定深入点了解一下String类. 要第一时间了解一个类,没有什么比官方的javaDoc ...

  8. Java爬取先知论坛文章

    Java爬取先知论坛文章 0x00 前言 上篇文章写了部分爬虫代码,这里给出一个完整的爬取先知论坛文章代码. 0x01 代码实现 pom.xml加入依赖: <dependencies> & ...

  9. Linux内核之 基本概念

    一直想写写Linux内核的文章,特别是进程这方面的,说实话,不好写,也不太敢写:)直到遇到了一本好书.<Linux内核设计与实现>,原书<Linux Kernel Developme ...

  10. Java 8中Lambda表达式默认方法的模板方法模式,你够了解么?

    为了以更简单的术语描述模板方法,考虑这个场景:假设在一个工作流系统中,为了完成任务,有4个任务必须以给定的执行顺序执行.在这4个任务中,不同工作流系统的实现可以根据自身情况自定义任务的执行内容. 模板 ...