From 81a7fa8e4537cae1b1afd68c4978be213f26487c Mon Sep 17 00:00:00 2001 From: yhaili Date: Wed, 17 Jun 2020 14:43:28 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90-?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=9C=AC=E4=BA=BA=E6=95=B0=E6=8D=AE=EF=BC=88?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=8E=A7=E5=88=B6=E5=8F=AF=E9=80=89=EF=BC=9A?= =?UTF-8?q?=E4=BB=85=E9=83=A8=E9=97=A8=E3=80=81=E4=BB=85=E6=9C=AC=E4=BA=BA?= =?UTF-8?q?=E3=80=81=E9=83=A8=E9=97=A8+=E6=9C=AC=E4=BA=BA=EF=BC=89=202?= =?UTF-8?q?=E3=80=81=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90-=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E8=87=AA=E5=8A=A8=E6=B3=A8=E5=85=A5=E5=92=8C=E6=89=8B?= =?UTF-8?q?=E5=8A=A8=E6=B3=A8=E5=85=A5=EF=BC=88=E5=9C=A8xml=E4=B8=AD?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E7=82=B9=E4=BD=8D=E7=AC=A6=E6=B3=A8=E5=85=A5?= =?UTF-8?q?=EF=BC=89=203=E3=80=81=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90-?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=AD=97=E6=AE=B5=E5=90=8D=E5=8F=8A=E8=A1=A8?= =?UTF-8?q?=E5=88=AB=E5=90=8D=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pigx/common/data/datascope/DataScope.java | 159 +++++++++++++++++- .../data/datascope/DataScopeHandle.java | 9 +- .../data/datascope/DataScopeInterceptor.java | 49 ++++-- .../datascope/PigxDefaultDatascopeHandle.java | 86 ++++++++-- .../common/data/enums/DataScopeFieldEnum.java | 55 ++++++ .../common/data/enums/DataScopeTypeEnum.java | 14 +- 6 files changed, 337 insertions(+), 35 deletions(-) create mode 100644 pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/enums/DataScopeFieldEnum.java diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScope.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScope.java index 8b36f7dc6..7bb88f275 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScope.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScope.java @@ -17,10 +17,12 @@ package com.pig4cloud.pigx.common.data.datascope; +import com.pig4cloud.pigx.common.data.enums.DataScopeFieldEnum; import lombok.Data; import lombok.EqualsAndHashCode; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -28,22 +30,173 @@ import java.util.List; * @author lengleng * @date 2018/8/30 * 数据权限查询参数 + * + * update by yhaili2009@163.com at 2020/6/17 + * 1、支持本人数据权限过滤; + * 2、支持自动注入、手动注入; + * 3、支持字段名称及表别名设置; */ @Data @EqualsAndHashCode(callSuper = true) public class DataScope extends HashMap { /** - * 限制范围的字段名称 + * sql中的占位符,需要xml中和此处一致,会被替换为真正的数据权限语句 + * add by yhaili2009@163.com at 2020/6/17 + */ + private String sqlPlaceholder = "[scope.scopeSql]"; + /** + * 用户ID的引用别名(autoInj为false时会用到) + * add by yhaili2009@163.com at 2020/6/17 + */ + private String userAlias; + /** + * 部门ID的引用别名(autoInj为false时会用到) + * add by yhaili2009@163.com at 2020/6/17 + */ + private String deptAlias; + /** + * 数据权限 sql语句,用于在自定义sql中引入 + * add by yhaili2009@163.com at 2020/6/17 + */ + private String scopeSql = ""; + /** + * 是否自动注入数据权限的sql, 为false时,需要自己在sql中通过 scopeSql 引入 + * add by yhaili2009@163.com at 2020/6/17 + */ + private boolean autoInj = true; + /** + * 限制范围的字段名称(用户) + * add by yhaili2009@163.com at 2020/6/17 + */ + private String userScopeName = "user_id"; + /** + * 限制范围的字段名称(部门) */ private String scopeName = "dept_id"; /** - * 具体的数据范围 + * 具体的数据范围(部门) */ - private List deptIds = new ArrayList<>(); + private List scopeIds = new ArrayList<>(); /** * 是否只查询本部门 */ private Boolean isOnly = false; + + /** + * 数据权限字段 + * add by yhaili2009@163.com at 2020/6/17 + */ + private DataScopeFieldEnum scopeField; + + public DataScope() { + this(DataScopeFieldEnum.DEPT); + } + + public DataScope(DataScopeFieldEnum scopeField) { + this.scopeField = scopeField; + } + + /** + * 仅控制用户数据权限 + * @return + */ + public static DataScope onlyUser() { + return new DataScope(DataScopeFieldEnum.USER); + } + + /** + * 仅控制部门数据权限 + * @return + */ + public static DataScope onlyDept() { + return new DataScope(DataScopeFieldEnum.DEPT); + } + + /** + * 可控制部门和用户数据权限 + * @return + */ + public static DataScope deptAndUser() { + return new DataScope(DataScopeFieldEnum.DEPT_AND_USER); + } + + /** + * 是否开启自动注入权限sql + * @param autoInj + * @return + */ + public DataScope autoInj(boolean autoInj) { + this.autoInj = autoInj; + return this; + } + + /** + * 设置部门ID引用的别名 + * @param deptAlias + * @return + */ + public DataScope deptAlias(String deptAlias) { + this.deptAlias = deptAlias; + return this; + } + + /** + * 设置用户ID引用的别名 + * @param userAlias + * @return + */ + public DataScope userAlias(String userAlias) { + this.userAlias = userAlias; + return this; + } + + /** + * 设置部门字段名 + * @param deptScopeName + * @return + */ + public DataScope deptScopeName(String deptScopeName) { + this.scopeName = deptScopeName; + return this; + } + + /** + * 设置用户字段名 + * @param userScopeName + * @return + */ + public DataScope userScopeName(String userScopeName) { + this.userScopeName = userScopeName; + return this; + } + + /** + * 设置数据权限 sql占位符 + * @param sqlPlaceholder + * @return + */ + public DataScope sqlPlaceholder(String sqlPlaceholder) { + this.sqlPlaceholder = sqlPlaceholder; + return this; + } + + /** + * 自定义可以查看的部门ID + * @param deptId + * @return + */ + public DataScope scopeIds(Integer ...deptId) { + this.scopeIds.addAll(Arrays.asList(deptId)); + return this; + } + + /** + * 权限sql不能在其他地方修改 + * @param scopeSql + */ + protected void setScopeSql(String scopeSql) { + this.scopeSql = scopeSql; + } } diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeHandle.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeHandle.java index 011607099..674da6250 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeHandle.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeHandle.java @@ -17,8 +17,6 @@ package com.pig4cloud.pigx.common.data.datascope; -import java.util.List; - /** * @author lengleng * @date 2019-09-07 @@ -30,8 +28,11 @@ public interface DataScopeHandle { /** * 计算用户数据权限 * - * @param deptList + * @param dataScope * @return + * + * update by yhaili2009@163.com at 2020/6/17 + * 修改参数 List 为 DataScope */ - Boolean calcScope(List deptList); + Boolean calcScope(DataScope dataScope); } diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeInterceptor.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeInterceptor.java index 7b0b262d6..386da6050 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeInterceptor.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/DataScopeInterceptor.java @@ -17,7 +17,6 @@ package com.pig4cloud.pigx.common.data.datascope; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import com.baomidou.mybatisplus.core.toolkit.PluginUtils; import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler; @@ -43,6 +42,11 @@ import java.util.Properties; * @date 2018/12/26 *

* mybatis 数据权限拦截器 + * + * update by yhaili2009@163.com at 2020/6/17 + * 1、支持本人数据权限过滤; + * 2、支持自动注入、手动注入; + * 3、支持字段名称及表别名设置; */ @Slf4j @AllArgsConstructor @@ -56,11 +60,6 @@ public class DataScopeInterceptor extends AbstractSqlParserHandler implements In StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget()); MetaObject metaObject = SystemMetaObject.forObject(statementHandler); this.sqlParser(metaObject); - // 先判断是不是SELECT操作 - MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); - if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) { - return invocation.proceed(); - } BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql"); String originalSql = boundSql.getSql(); @@ -72,14 +71,38 @@ public class DataScopeInterceptor extends AbstractSqlParserHandler implements In return invocation.proceed(); } - String scopeName = dataScope.getScopeName(); - List deptIds = dataScope.getDeptIds(); - // 优先获取赋值数据 - if (CollUtil.isEmpty(deptIds) && dataScopeHandle.calcScope(deptIds)) { - return invocation.proceed(); + /** + * 这里分自动注入和手动注入处理; 自动注入维持原来的逻辑不变 + * update by yhaili2009@163.com at 2020/6/17 + */ + if (dataScope.isAutoInj()) { + // 先判断是不是SELECT操作 + MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); + if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) { + return invocation.proceed(); + } + + // 优先获取赋值数据 + if (dataScopeHandle.calcScope(dataScope)) { + return invocation.proceed(); + } + + String scopeName = dataScope.getScopeName(); + List scopeIds = dataScope.getScopeIds(); + + String join = CollectionUtil.join(scopeIds, ","); + originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")"; } - String join = CollectionUtil.join(deptIds, ","); - originalSql = "select * from (" + originalSql + ") temp_data_scope where temp_data_scope." + scopeName + " in (" + join + ")"; + /** + * 手动插入sql中(通过字符串占位) + * add by yhaili2009@163.com at 2020/6/17 + */ + else { + dataScopeHandle.calcScope(dataScope); + + originalSql = originalSql.replace(dataScope.getSqlPlaceholder(), dataScope.getScopeSql() + " "); + } + metaObject.setValue("delegate.boundSql.sql", originalSql); return invocation.proceed(); } diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/PigxDefaultDatascopeHandle.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/PigxDefaultDatascopeHandle.java index 2a1191256..85904cc12 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/PigxDefaultDatascopeHandle.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/datascope/PigxDefaultDatascopeHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2025, lengleng All rights reserved. + * Copyright (c) 2018-2025, ihealth All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -12,46 +12,75 @@ * Neither the name of the pig4cloud.com developer nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) + * Author: ihealth */ package com.pig4cloud.pigx.common.data.datascope; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.pig4cloud.pigx.admin.api.entity.SysDeptRelation; import com.pig4cloud.pigx.admin.api.entity.SysRole; import com.pig4cloud.pigx.admin.api.feign.RemoteDataScopeService; import com.pig4cloud.pigx.common.core.constant.SecurityConstants; +import com.pig4cloud.pigx.common.data.enums.DataScopeFieldEnum; import com.pig4cloud.pigx.common.data.enums.DataScopeTypeEnum; import com.pig4cloud.pigx.common.security.service.PigxUser; import com.pig4cloud.pigx.common.security.util.SecurityUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; /** - * @author lengleng + * @author ihealth * @date 2019-09-07 *

* 默认data scope 判断处理器 + * + * update by yhaili2009@163.com at 2020/6/17 + * 1、支持本人数据权限过滤; + * 2、支持自动注入、手动注入; + * 3、支持字段名称及表别名设置; */ public class PigxDefaultDatascopeHandle implements DataScopeHandle { + @Autowired private RemoteDataScopeService dataScopeService; /** * 计算用户数据权限 * - * @param deptList + * @param dataScope * @return */ @Override - public Boolean calcScope(List deptList) { + public Boolean calcScope(DataScope dataScope) { + // 默认数据权限sql为空,即不限制 + dataScope.setScopeSql(""); + + // 优先获取赋值数据 + if (CollUtil.isNotEmpty(dataScope.getScopeIds())) { + return false; + } + + List scopeList = dataScope.getScopeIds(); + if (scopeList == null) { + scopeList = new ArrayList<>(); + } + // 默认为部门数据权限控制 +// dataScope.setScopeName(DEPT_SCOPE_NAME); + PigxUser user = SecurityUtils.getUser(); + // 当前用户为空(一般后台处理程序),给所有数据 + if (user == null) { + return true; + } List roleIdList = user.getAuthorities() .stream().map(GrantedAuthority::getAuthority) .filter(authority -> authority.startsWith(SecurityConstants.ROLE)) @@ -62,27 +91,62 @@ public class PigxDefaultDatascopeHandle implements DataScopeHandle { .min(Comparator.comparingInt(SysRole::getDsType)).get(); Integer dsType = role.getDsType(); + // 仅支持用户字段的数据权限时,角色指定不是仅本人数据 + if (dataScope.getScopeField() == DataScopeFieldEnum.USER && dsType != DataScopeTypeEnum.OWN.getType()) { + return true; + } + // 仅支持部门字段数据权限时,角色指定只能查看仅本人数据 + if (dataScope.getScopeField() == DataScopeFieldEnum.DEPT && dsType == DataScopeTypeEnum.OWN.getType()) { + return true; + } + + // 默认为部门数据权限过滤 + String alias = dataScope.getDeptAlias(); + // 查询全部 if (DataScopeTypeEnum.ALL.getType() == dsType) { return true; } // 自定义 - if (DataScopeTypeEnum.CUSTOM.getType() == dsType) { + else if (DataScopeTypeEnum.CUSTOM.getType() == dsType) { String dsScope = role.getDsScope(); - deptList.addAll(Arrays.stream(dsScope.split(StrUtil.COMMA)) + scopeList.addAll(Arrays.stream(dsScope.split(StrUtil.COMMA)) .map(Integer::parseInt).collect(Collectors.toList())); } // 查询本级及其下级 - if (DataScopeTypeEnum.OWN_CHILD_LEVEL.getType() == dsType) { + else if (DataScopeTypeEnum.OWN_CHILD_LEVEL.getType() == dsType) { List deptIdList = dataScopeService.getDescendantList(user.getDeptId()) .getData().stream().map(SysDeptRelation::getDescendant) .collect(Collectors.toList()); - deptList.addAll(deptIdList); + scopeList.addAll(deptIdList); } // 只查询本级 - if (DataScopeTypeEnum.OWN_LEVEL.getType() == dsType) { - deptList.add(user.getDeptId()); + else if (DataScopeTypeEnum.OWN_LEVEL.getType() == dsType) { + scopeList.add(user.getDeptId()); } + /** + * 只查询本人 + * add by yhaili2009@163.com at 2020/6/17 + */ + else if (DataScopeTypeEnum.OWN.getType() == dsType) { + scopeList.add(user.getId()); + // 设置用户数据权限控制 + dataScope.setScopeName(dataScope.getUserScopeName()); + alias = dataScope.getUserAlias(); + } + + alias = StrUtil.isBlank(alias) ? "" : alias + "."; + if (scopeList.isEmpty()) { + // 没有任何权限,不返回任何数据 + dataScope.setScopeSql(" AND 1=0"); + } else if (scopeList.size() == 1) { + dataScope.setScopeSql(" AND " + alias + dataScope.getScopeName() + " = " + scopeList.get(0)); + } else { + String join = CollectionUtil.join(scopeList, ","); + dataScope.setScopeSql(" AND " + alias + dataScope.getScopeName() + " IN (" + join + ")"); + } + + dataScope.setScopeIds(scopeList); return false; } } diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/enums/DataScopeFieldEnum.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/enums/DataScopeFieldEnum.java new file mode 100644 index 000000000..2c90a3ec7 --- /dev/null +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/enums/DataScopeFieldEnum.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.pigx.common.data.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据权限支持的模式 + * @author yhaili2009@163.com + * @date 2020/6/17 + * + */ +@Getter +@AllArgsConstructor +public enum DataScopeFieldEnum { + /** + * 仅支持部门 + */ + DEPT(0, "仅部门"), + + /** + * 仅支持用户 + */ + USER(1, "仅用户"), + + /** + * 支持部门和用户 + */ + DEPT_AND_USER(2, "部门和用户"); + + /** + * 类型 + */ + private final int type; + /** + * 描述 + */ + private final String description; +} diff --git a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/enums/DataScopeTypeEnum.java b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/enums/DataScopeTypeEnum.java index 9e243af25..2b8a0cdc5 100644 --- a/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/enums/DataScopeTypeEnum.java +++ b/pigx-common/pigx-common-data/src/main/java/com/pig4cloud/pigx/common/data/enums/DataScopeTypeEnum.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2025, lengleng All rights reserved. + * Copyright (c) 2018-2025, ihealth All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -12,7 +12,7 @@ * Neither the name of the pig4cloud.com developer nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * Author: lengleng (wangiegie@gmail.com) + * Author: ihealth */ package com.pig4cloud.pigx.common.data.enums; @@ -21,7 +21,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; /** - * @author lengleng + * @author ihealth * @date 2018/12/26 *

* 数据权限类型 @@ -47,7 +47,13 @@ public enum DataScopeTypeEnum { /** * 本级 */ - OWN_LEVEL(3, "本级"); + OWN_LEVEL(3, "本级"), + + /** + * 本人 + * add by yhaili2009@163.com at 2020/6/17 + */ + OWN(4, "本人"); /** * 类型