diff --git a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/constant/DataPermissionConstants.java b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/constant/DataPermissionConstants.java new file mode 100644 index 00000000..33e79c66 --- /dev/null +++ b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/constant/DataPermissionConstants.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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() { + } +} \ No newline at end of file diff --git a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/exception/DataPermissionException.java b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/exception/DataPermissionException.java new file mode 100644 index 00000000..89d20d51 --- /dev/null +++ b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/exception/DataPermissionException.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + *

+ * 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 + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * 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); + } +} \ No newline at end of file diff --git a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/model/RoleData.java b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/model/RoleData.java index cbc6ef44..387c527a 100644 --- a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/model/RoleData.java +++ b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/model/RoleData.java @@ -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; } diff --git a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/model/UserData.java b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/model/UserData.java index dbf69a01..5844a1cc 100644 --- a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/model/UserData.java +++ b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/model/UserData.java @@ -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 roles; + private Set roles = Collections.emptySet(); /** * 部门 ID */ - private String deptId; + private Long deptId; - public String getUserId() { + public UserData() { + } + + public UserData(Long userId, Long deptId, Set 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 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(); + } } diff --git a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/filter/DataPermissionUserDataProvider.java b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/provider/DataPermissionUserDataProvider.java similarity index 94% rename from continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/filter/DataPermissionUserDataProvider.java rename to continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/provider/DataPermissionUserDataProvider.java index 729b9fd8..8bbd0182 100644 --- a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/filter/DataPermissionUserDataProvider.java +++ b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-core/src/main/java/top/continew/starter/extension/datapermission/provider/DataPermissionUserDataProvider.java @@ -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; diff --git a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-mp/src/main/java/top/continew/starter/extension/datapermission/autoconfigure/DataPermissionAutoConfiguration.java b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-mp/src/main/java/top/continew/starter/extension/datapermission/autoconfigure/DataPermissionAutoConfiguration.java index 0c03fa05..7d74fb22 100644 --- a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-mp/src/main/java/top/continew/starter/extension/datapermission/autoconfigure/DataPermissionAutoConfiguration.java +++ b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-mp/src/main/java/top/continew/starter/extension/datapermission/autoconfigure/DataPermissionAutoConfiguration.java @@ -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; /** diff --git a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-mp/src/main/java/top/continew/starter/extension/datapermission/handler/DefaultDataPermissionHandler.java b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-mp/src/main/java/top/continew/starter/extension/datapermission/handler/DefaultDataPermissionHandler.java index 8dfc0ff4..706cbab0 100644 --- a/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-mp/src/main/java/top/continew/starter/extension/datapermission/handler/DefaultDataPermissionHandler.java +++ b/continew-starter-extension/continew-starter-extension-datapermission/continew-starter-extension-datapermission-mp/src/main/java/top/continew/starter/extension/datapermission/handler/DefaultDataPermissionHandler.java @@ -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 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));