mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-09 02:58:38 +08:00
refactor(extension/datapermission): 优化数据权限模块代码
- 新增 DataPermissionConstants 和 DataPermissionException 类 - 重构 DataPermissionUserDataProvider 接口位置 - 优化 RoleData 和 UserData 类,使用 Long 类型替代 String 类型 - 重构 DefaultDataPermissionHandler 类,改进数据权限处理逻辑
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.extension.datapermission.constant;
|
||||
|
||||
/**
|
||||
* 数据权限常量
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.13.2
|
||||
*/
|
||||
public final class DataPermissionConstants {
|
||||
|
||||
/**
|
||||
* 数据库字段:祖先节点
|
||||
*/
|
||||
public static final String ANCESTORS_COLUMN = "ancestors";
|
||||
|
||||
/**
|
||||
* 方法名后缀:COUNT
|
||||
*/
|
||||
public static final String COUNT_METHOD_SUFFIX = "_COUNT";
|
||||
|
||||
private DataPermissionConstants() {
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.extension.datapermission.exception;
|
||||
|
||||
import top.continew.starter.core.exception.BaseException;
|
||||
|
||||
/**
|
||||
* 数据权限异常
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.13.2
|
||||
*/
|
||||
public class DataPermissionException extends BaseException {
|
||||
|
||||
public DataPermissionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DataPermissionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public static DataPermissionException unsupportedDataScope(String dataScope) {
|
||||
return new DataPermissionException("Unsupported data scope: " + dataScope);
|
||||
}
|
||||
|
||||
public static DataPermissionException unsupportedDatabase(String database) {
|
||||
return new DataPermissionException("Unsupported database for data permission: " + database);
|
||||
}
|
||||
|
||||
public static DataPermissionException invalidUserData(String message) {
|
||||
return new DataPermissionException("Invalid user data: " + message);
|
||||
}
|
||||
|
||||
public static DataPermissionException methodNotFound(String mappedStatementId) {
|
||||
return new DataPermissionException("Method not found for data permission: " + mappedStatementId);
|
||||
}
|
||||
}
|
@@ -29,7 +29,7 @@ public class RoleData {
|
||||
/**
|
||||
* 角色 ID
|
||||
*/
|
||||
private String roleId;
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 数据权限
|
||||
@@ -39,16 +39,16 @@ public class RoleData {
|
||||
public RoleData() {
|
||||
}
|
||||
|
||||
public RoleData(String roleId, DataScope dataScope) {
|
||||
public RoleData(Long roleId, DataScope dataScope) {
|
||||
this.roleId = roleId;
|
||||
this.dataScope = dataScope;
|
||||
}
|
||||
|
||||
public String getRoleId() {
|
||||
public Long getRoleId() {
|
||||
return roleId;
|
||||
}
|
||||
|
||||
public void setRoleId(String roleId) {
|
||||
public void setRoleId(Long roleId) {
|
||||
this.roleId = roleId;
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
package top.continew.starter.extension.datapermission.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -29,23 +30,32 @@ public class UserData {
|
||||
/**
|
||||
* 用户 ID
|
||||
*/
|
||||
private String userId;
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 角色列表
|
||||
*/
|
||||
private Set<RoleData> roles;
|
||||
private Set<RoleData> roles = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* 部门 ID
|
||||
*/
|
||||
private String deptId;
|
||||
private Long deptId;
|
||||
|
||||
public String getUserId() {
|
||||
public UserData() {
|
||||
}
|
||||
|
||||
public UserData(Long userId, Long deptId, Set<RoleData> roles) {
|
||||
this.userId = userId;
|
||||
this.deptId = deptId;
|
||||
this.roles = roles != null ? roles : Collections.emptySet();
|
||||
}
|
||||
|
||||
public Long getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
public void setUserId(Long userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
@@ -54,14 +64,23 @@ public class UserData {
|
||||
}
|
||||
|
||||
public void setRoles(Set<RoleData> roles) {
|
||||
this.roles = roles;
|
||||
this.roles = roles != null ? roles : Collections.emptySet();
|
||||
}
|
||||
|
||||
public String getDeptId() {
|
||||
public Long getDeptId() {
|
||||
return deptId;
|
||||
}
|
||||
|
||||
public void setDeptId(String deptId) {
|
||||
public void setDeptId(Long deptId) {
|
||||
this.deptId = deptId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户数据是否有效
|
||||
*
|
||||
* @return 是否有效
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return userId != null && deptId != null && !roles.isEmpty();
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.extension.datapermission.filter;
|
||||
package top.continew.starter.extension.datapermission.provider;
|
||||
|
||||
import top.continew.starter.extension.datapermission.model.UserData;
|
||||
|
@@ -28,7 +28,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
||||
import top.continew.starter.extension.datapermission.filter.DataPermissionUserDataProvider;
|
||||
import top.continew.starter.extension.datapermission.provider.DataPermissionUserDataProvider;
|
||||
import top.continew.starter.extension.datapermission.handler.DefaultDataPermissionHandler;
|
||||
|
||||
/**
|
||||
|
@@ -46,8 +46,10 @@ import top.continew.starter.core.constant.StringConstants;
|
||||
import top.continew.starter.data.enums.DatabaseType;
|
||||
import top.continew.starter.data.util.MetaUtils;
|
||||
import top.continew.starter.extension.datapermission.annotation.DataPermission;
|
||||
import top.continew.starter.extension.datapermission.constant.DataPermissionConstants;
|
||||
import top.continew.starter.extension.datapermission.enums.DataScope;
|
||||
import top.continew.starter.extension.datapermission.filter.DataPermissionUserDataProvider;
|
||||
import top.continew.starter.extension.datapermission.exception.DataPermissionException;
|
||||
import top.continew.starter.extension.datapermission.provider.DataPermissionUserDataProvider;
|
||||
import top.continew.starter.extension.datapermission.model.RoleData;
|
||||
import top.continew.starter.extension.datapermission.model.UserData;
|
||||
|
||||
@@ -62,7 +64,6 @@ public class DefaultDataPermissionHandler implements DataPermissionHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DefaultDataPermissionHandler.class);
|
||||
private final DataPermissionUserDataProvider dataPermissionUserDataProvider;
|
||||
private static final DataSource dataSource = SpringUtil.getBean(DataSource.class);
|
||||
|
||||
public DefaultDataPermissionHandler(DataPermissionUserDataProvider dataPermissionUserDataProvider) {
|
||||
this.dataPermissionUserDataProvider = dataPermissionUserDataProvider;
|
||||
@@ -71,26 +72,47 @@ public class DefaultDataPermissionHandler implements DataPermissionHandler {
|
||||
@Override
|
||||
public Expression getSqlSegment(Expression where, String mappedStatementId) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(mappedStatementId.substring(0, mappedStatementId
|
||||
.lastIndexOf(StringConstants.DOT)));
|
||||
String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(StringConstants.DOT) + 1);
|
||||
Method[] methodArr = clazz.getMethods();
|
||||
for (Method method : methodArr) {
|
||||
DataPermission dataPermission = method.getAnnotation(DataPermission.class);
|
||||
String name = method.getName();
|
||||
if (dataPermission == null || !CharSequenceUtil.equalsAny(methodName, name, name + "_COUNT")) {
|
||||
continue;
|
||||
}
|
||||
if (dataPermissionUserDataProvider.isFilter()) {
|
||||
return buildDataScopeFilter(dataPermission, where);
|
||||
}
|
||||
DataPermission dataPermission = findDataPermissionAnnotation(mappedStatementId);
|
||||
if (dataPermission != null && dataPermissionUserDataProvider.isFilter()) {
|
||||
return buildDataScopeFilter(dataPermission, where);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
} catch (Exception e) {
|
||||
log.error("Data permission handler build data scope filter occurred an error: {}.", e.getMessage(), e);
|
||||
}
|
||||
return where;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找数据权限注解
|
||||
*
|
||||
* @param mappedStatementId Mapper 方法 ID
|
||||
* @return 数据权限注解
|
||||
*/
|
||||
private DataPermission findDataPermissionAnnotation(String mappedStatementId) {
|
||||
try {
|
||||
int lastDotIndex = mappedStatementId.lastIndexOf(StringConstants.DOT);
|
||||
if (lastDotIndex == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String className = mappedStatementId.substring(0, lastDotIndex);
|
||||
String methodName = mappedStatementId.substring(lastDotIndex + 1);
|
||||
|
||||
Class<?> clazz = Class.forName(className);
|
||||
Method[] methods = clazz.getMethods();
|
||||
|
||||
for (Method method : methods) {
|
||||
String name = method.getName();
|
||||
if (CharSequenceUtil.equalsAny(methodName, name, name + DataPermissionConstants.COUNT_METHOD_SUFFIX)) {
|
||||
return method.getAnnotation(DataPermission.class);
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw DataPermissionException.methodNotFound(mappedStatementId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建数据范围过滤条件
|
||||
*
|
||||
@@ -99,23 +121,29 @@ public class DefaultDataPermissionHandler implements DataPermissionHandler {
|
||||
* @return 构建后查询条件
|
||||
*/
|
||||
private Expression buildDataScopeFilter(DataPermission dataPermission, Expression where) {
|
||||
Expression expression = null;
|
||||
UserData userData = dataPermissionUserDataProvider.getUserData();
|
||||
if (userData == null || !userData.isValid()) {
|
||||
throw DataPermissionException.invalidUserData("User data is null or invalid");
|
||||
}
|
||||
|
||||
Expression expression = null;
|
||||
Set<RoleData> roles = userData.getRoles();
|
||||
|
||||
for (RoleData roleData : roles) {
|
||||
DataScope dataScope = roleData.getDataScope();
|
||||
if (DataScope.ALL.equals(dataScope)) {
|
||||
return where;
|
||||
}
|
||||
switch (dataScope) {
|
||||
case DEPT_AND_CHILD -> expression = this
|
||||
.buildDeptAndChildExpression(dataPermission, userData, expression);
|
||||
case DEPT -> expression = this.buildDeptExpression(dataPermission, userData, expression);
|
||||
case SELF -> expression = this.buildSelfExpression(dataPermission, userData, expression);
|
||||
case CUSTOM -> expression = this.buildCustomExpression(dataPermission, roleData, expression);
|
||||
default -> throw new IllegalArgumentException("暂不支持 [%s] 数据权限".formatted(dataScope));
|
||||
}
|
||||
|
||||
expression = switch (dataScope) {
|
||||
case DEPT_AND_CHILD -> buildDeptAndChildExpression(dataPermission, userData, expression);
|
||||
case DEPT -> buildDeptExpression(dataPermission, userData, expression);
|
||||
case SELF -> buildSelfExpression(dataPermission, userData, expression);
|
||||
case CUSTOM -> buildCustomExpression(dataPermission, roleData, expression);
|
||||
default -> throw DataPermissionException.unsupportedDataScope(dataScope.toString());
|
||||
};
|
||||
}
|
||||
|
||||
return where != null ? new AndExpression(where, new ParenthesedExpressionList<>(expression)) : expression;
|
||||
}
|
||||
|
||||
@@ -144,18 +172,19 @@ public class DefaultDataPermissionHandler implements DataPermissionHandler {
|
||||
equalsTo.setLeftExpression(new Column(dataPermission.id()));
|
||||
equalsTo.setRightExpression(new LongValue(userData.getDeptId()));
|
||||
|
||||
DatabaseType databaseType = MetaUtils.getDatabaseType(dataSource);
|
||||
DatabaseType databaseType = MetaUtils.getDatabaseType(SpringUtil.getBean(DataSource.class));
|
||||
Expression inSetExpression;
|
||||
if (DatabaseType.MYSQL.getDatabase().equalsIgnoreCase(databaseType.getDatabase())) {
|
||||
Function findInSetFunction = new Function();
|
||||
findInSetFunction.setName("find_in_set");
|
||||
findInSetFunction.setParameters(new ExpressionList(new LongValue(userData
|
||||
.getDeptId()), new Column("ancestors")));
|
||||
.getDeptId()), new Column(DataPermissionConstants.ANCESTORS_COLUMN)));
|
||||
inSetExpression = findInSetFunction;
|
||||
} else if (DatabaseType.POSTGRE_SQL.getDatabase().equalsIgnoreCase(databaseType.getDatabase())) {
|
||||
// 构建 concat 函数
|
||||
Function concatFunction = new Function("concat");
|
||||
concatFunction.setParameters(new ExpressionList<>(new Column("ancestors"), new StringValue(",")));
|
||||
concatFunction
|
||||
.setParameters(new ExpressionList<>(new Column(DataPermissionConstants.ANCESTORS_COLUMN), new StringValue(",")));
|
||||
|
||||
// 创建 LIKE 函数
|
||||
LikeExpression likeExpression = new LikeExpression();
|
||||
@@ -163,7 +192,7 @@ public class DefaultDataPermissionHandler implements DataPermissionHandler {
|
||||
likeExpression.setRightExpression(new StringValue("%," + userData.getDeptId() + ",%"));
|
||||
inSetExpression = likeExpression;
|
||||
} else {
|
||||
throw new IllegalArgumentException("暂不支持 [%s] 数据权限".formatted(""));
|
||||
throw DataPermissionException.unsupportedDatabase(databaseType.getDatabase());
|
||||
}
|
||||
|
||||
select.setWhere(new OrExpression(equalsTo, inSetExpression));
|
||||
|
Reference in New Issue
Block a user