From 83514b92518ee412398490b4a71f9657ba79266b Mon Sep 17 00:00:00 2001 From: Charles7c Date: Thu, 24 Jul 2025 22:34:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84=20CRUD=20API=20?= =?UTF-8?q?=E6=9D=83=E9=99=90=E6=8E=A7=E5=88=B6=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=20CrudApiPermissionPrefixCache=20=E7=BC=93=E5=AD=98=E6=9D=83?= =?UTF-8?q?=E9=99=90=E5=89=8D=E7=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 CrudApiPermissionPrefixCache 类用于缓存 CRUD API权限前缀 - 修改 SaTokenConfiguration,为使用 @CrudRequestMapping 注解的 Controller缓存权限前缀 - 重构 BaseController 中的权限校验逻辑,使用缓存的权限前缀 - 更新 SmsConfigController 和 SmsLogController 中的 @CrudRequestMapping 注解路径 --- .../base/controller/BaseController.java | 10 +-- .../crud/CrudApiPermissionPrefixCache.java | 85 +++++++++++++++++++ .../config/satoken/SaTokenConfiguration.java | 11 ++- .../controller/SmsConfigController.java | 2 +- .../system/controller/SmsLogController.java | 2 +- 5 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 continew-common/src/main/java/top/continew/admin/common/config/crud/CrudApiPermissionPrefixCache.java diff --git a/continew-common/src/main/java/top/continew/admin/common/base/controller/BaseController.java b/continew-common/src/main/java/top/continew/admin/common/base/controller/BaseController.java index 64c2261c..7ec76035 100644 --- a/continew-common/src/main/java/top/continew/admin/common/base/controller/BaseController.java +++ b/continew-common/src/main/java/top/continew/admin/common/base/controller/BaseController.java @@ -22,11 +22,9 @@ import cn.dev33.satoken.context.model.SaRequest; import cn.dev33.satoken.sign.template.SaSignTemplate; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.annotation.AnnotationUtil; -import cn.hutool.core.text.CharSequenceUtil; import top.continew.admin.common.base.service.BaseService; -import top.continew.starter.core.constant.StringConstants; +import top.continew.admin.common.config.crud.CrudApiPermissionPrefixCache; import top.continew.starter.extension.crud.annotation.CrudApi; -import top.continew.starter.extension.crud.annotation.CrudRequestMapping; import top.continew.starter.extension.crud.controller.AbstractCrudController; import top.continew.starter.extension.crud.enums.Api; @@ -64,11 +62,9 @@ public class BaseController, L, D, Q, C> exten return; } // 校验权限,例如:创建用户接口(POST /system/user) => 校验 system:user:create 权限 - CrudRequestMapping crudRequestMapping = targetClass.getDeclaredAnnotation(CrudRequestMapping.class); - String path = crudRequestMapping.value(); - String prefix = String.join(StringConstants.COLON, CharSequenceUtil.splitTrim(path, StringConstants.SLASH)); + String permissionPrefix = CrudApiPermissionPrefixCache.get(targetClass); String apiName = getApiName(crudApi.value()); - StpUtil.checkPermission("%s:%s".formatted(prefix, apiName.toLowerCase())); + StpUtil.checkPermission("%s:%s".formatted(permissionPrefix, apiName.toLowerCase())); } /** diff --git a/continew-common/src/main/java/top/continew/admin/common/config/crud/CrudApiPermissionPrefixCache.java b/continew-common/src/main/java/top/continew/admin/common/config/crud/CrudApiPermissionPrefixCache.java new file mode 100644 index 00000000..0735b4ba --- /dev/null +++ b/continew-common/src/main/java/top/continew/admin/common/config/crud/CrudApiPermissionPrefixCache.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.admin.common.config.crud; + +import cn.hutool.core.util.StrUtil; +import top.continew.starter.core.constant.StringConstants; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * CRUD API 权限前缀缓存 + * + * @author Charles7c + * @since 2025/7/24 22:14 + */ +public class CrudApiPermissionPrefixCache { + + private static final Map, String> PERMISSION_PREFIX_CACHE = new HashMap<>(); + + /** + * 存储CRUD API权限前缀 + * + * @param controllerClazz 控制器类 + * @param path 路径 + */ + public static void put(Class controllerClazz, String path) { + String permissionPrefix = parsePermissionPrefix(path); + PERMISSION_PREFIX_CACHE.put(controllerClazz, permissionPrefix); + } + + /** + * 获取CRUD API权限前缀 + * + * @param controllerClazz 控制器类 + * @return 权限前缀 + */ + public static String get(Class controllerClazz) { + return PERMISSION_PREFIX_CACHE.get(controllerClazz); + } + + /** + * 清空缓存 + */ + public static void clear() { + PERMISSION_PREFIX_CACHE.clear(); + } + + /** + * 解析权限前缀(解析路径获取模块名和资源名) + * + *

+ * 例如:/system/user => system:user
+ * /system/dict/item => system:dictItem + *

+ * + * @param path 路径 + * @return 权限前缀 + */ + private static String parsePermissionPrefix(String path) { + List pathSegmentList = StrUtil.splitTrim(path, StringConstants.SLASH); + if (pathSegmentList.size() < 2) { + throw new IllegalArgumentException("无效的 @CrudRequestMapping 路径配置:" + path); + } + String moduleName = pathSegmentList.get(0); + String resourceName = StrUtil.toCamelCase(String.join(StringConstants.UNDERLINE, pathSegmentList + .subList(1, pathSegmentList.size()))); + return "%s:%s".formatted(moduleName, resourceName); + } +} diff --git a/continew-server/src/main/java/top/continew/admin/config/satoken/SaTokenConfiguration.java b/continew-server/src/main/java/top/continew/admin/config/satoken/SaTokenConfiguration.java index d4f44101..5ac97c72 100644 --- a/continew-server/src/main/java/top/continew/admin/config/satoken/SaTokenConfiguration.java +++ b/continew-server/src/main/java/top/continew/admin/config/satoken/SaTokenConfiguration.java @@ -35,6 +35,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.event.EventListener; import org.springframework.core.annotation.AnnotationUtils; +import top.continew.admin.common.config.crud.CrudApiPermissionPrefixCache; import top.continew.admin.common.context.UserContext; import top.continew.admin.common.context.UserContextHolder; import top.continew.admin.open.sign.OpenApiSignTemplate; @@ -113,11 +114,15 @@ public class SaTokenConfiguration { if (AopUtils.isAopProxy(bean)) { clazz = AopProxyUtils.ultimateTargetClass(bean); } - // 使用 @CrudRequestMapping 的 Controller,如果使用了 @SaIgnore 注解,则表示忽略校验 + // 使用 @CrudRequestMapping 的 Controller,如果使用了 @SaIgnore 注解,则表示忽略认证和权限校验 CrudRequestMapping crudRequestMapping = AnnotationUtils.findAnnotation(clazz, CrudRequestMapping.class); SaIgnore saIgnore = AnnotationUtils.findAnnotation(clazz, SaIgnore.class); - if (crudRequestMapping != null && saIgnore != null) { - return crudRequestMapping.value() + StringConstants.PATH_PATTERN; + if (crudRequestMapping != null) { + if (saIgnore != null) { + return crudRequestMapping.value() + StringConstants.PATH_PATTERN; + } + // 缓存权限前缀 + CrudApiPermissionPrefixCache.put(clazz, crudRequestMapping.value()); } return null; }).filter(Objects::nonNull).toList(); diff --git a/continew-system/src/main/java/top/continew/admin/system/controller/SmsConfigController.java b/continew-system/src/main/java/top/continew/admin/system/controller/SmsConfigController.java index 934b732e..8bcc47b0 100644 --- a/continew-system/src/main/java/top/continew/admin/system/controller/SmsConfigController.java +++ b/continew-system/src/main/java/top/continew/admin/system/controller/SmsConfigController.java @@ -41,7 +41,7 @@ import top.continew.starter.extension.crud.enums.Api; */ @Tag(name = "短信配置管理 API") @RestController -@CrudRequestMapping(value = "/system/smsConfig", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.BATCH_DELETE}) +@CrudRequestMapping(value = "/system/sms/config", api = {Api.PAGE, Api.GET, Api.CREATE, Api.UPDATE, Api.BATCH_DELETE}) public class SmsConfigController extends BaseController { @Operation(summary = "设为默认配置", description = "设为默认配置") diff --git a/continew-system/src/main/java/top/continew/admin/system/controller/SmsLogController.java b/continew-system/src/main/java/top/continew/admin/system/controller/SmsLogController.java index 7a2cb296..a77ddbc0 100644 --- a/continew-system/src/main/java/top/continew/admin/system/controller/SmsLogController.java +++ b/continew-system/src/main/java/top/continew/admin/system/controller/SmsLogController.java @@ -35,6 +35,6 @@ import top.continew.starter.extension.crud.enums.Api; */ @Tag(name = "短信日志管理 API") @RestController -@CrudRequestMapping(value = "/system/smsLog", api = {Api.PAGE, Api.GET, Api.BATCH_DELETE, Api.EXPORT}) +@CrudRequestMapping(value = "/system/sms/log", api = {Api.PAGE, Api.GET, Api.BATCH_DELETE, Api.EXPORT}) public class SmsLogController extends BaseController { } \ No newline at end of file