1、数据权限-支持本人数据(权限控制可选:仅部门、仅本人、部门+本人)

2、数据权限-支持自动注入和手动注入(在xml中通过点位符注入)
3、数据权限-支持字段名及表别名设置
This commit is contained in:
yhaili committed 2020-06-17 14:43:28 +08:00
1 parent 2cbcea03f6
commit 81a7fa8e45
6 files changed
+337 -35

No files matched your search

@@ -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<Integer> deptIds = new ArrayList<>();
private List<Integer> 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;
}
}
@@ -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<Integer> 为 DataScope
*/
Boolean calcScope(List<Integer> deptList);
Boolean calcScope(DataScope dataScope);
}
@@ -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
* <p>
* 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<Integer> 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<Integer> 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();
}
@@ -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
* <p>
* 默认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<Integer> deptList) {
public Boolean calcScope(DataScope dataScope) {
// 默认数据权限sql为空,即不限制
dataScope.setScopeSql("");
// 优先获取赋值数据
if (CollUtil.isNotEmpty(dataScope.getScopeIds())) {
return false;
}
List<Integer> scopeList = dataScope.getScopeIds();
if (scopeList == null) {
scopeList = new ArrayList<>();
}
// 默认为部门数据权限控制
// dataScope.setScopeName(DEPT_SCOPE_NAME);
PigxUser user = SecurityUtils.getUser();
// 当前用户为空(一般后台处理程序),给所有数据
if (user == null) {
return true;
}
List<String> 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<Integer> 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;
}
}
@@ -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;
}
@@ -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
* <p>
* 数据权限类型
@@ -47,7 +47,13 @@ public enum DataScopeTypeEnum {
/**
* 本级
*/
OWN_LEVEL(3, "本级");
OWN_LEVEL(3, "本级"),
/**
* 本人
* add by yhaili2009@163.com at 2020/6/17
*/
OWN(4, "本人");
/**
* 类型