From be86cdfd517d65fcaf513f1f6b6daf11d5f12533 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Mon, 5 May 2025 09:33:34 +0800 Subject: [PATCH] =?UTF-8?q?reactor=EF=BC=9A@TenantIgnore=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=9C=A8=20Controller=20=E6=97=B6=EF=BC=8C=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=B7=BB=E5=8A=A0=E5=88=B0=20TenantProperties=20?= =?UTF-8?q?=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/YudaoTenantAutoConfiguration.java | 43 ++++++++++++++++++- .../controller/admin/file/FileController.java | 2 + .../admin/open/MpOpenController.java | 43 ++++++++++--------- .../admin/notify/PayNotifyController.java | 4 ++ .../admin/captcha/CaptchaController.java | 3 ++ .../admin/sms/SmsCallbackController.java | 5 +++ .../admin/tenant/TenantController.java | 4 ++ .../src/main/resources/application.yaml | 9 ---- 8 files changed, 83 insertions(+), 30 deletions(-) diff --git a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java index a804cce871..c142e3dbb4 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/config/YudaoTenantAutoConfiguration.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.tenant.config; import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.framework.redis.config.YudaoCacheProperties; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnoreAspect; import cn.iocoder.yudao.framework.tenant.core.db.TenantDatabaseInterceptor; import cn.iocoder.yudao.framework.tenant.core.job.TenantJobAspect; @@ -19,11 +20,13 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler; import cn.iocoder.yudao.module.system.api.tenant.TenantApi; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor; +import jakarta.annotation.Resource; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.data.redis.cache.BatchStrategies; @@ -32,14 +35,24 @@ import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import org.springframework.web.util.pattern.PathPattern; +import java.util.Map; import java.util.Objects; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + @AutoConfiguration @ConditionalOnProperty(prefix = "yudao.tenant", value = "enable", matchIfMissing = true) // 允许使用 yudao.tenant.enable=false 禁用多租户 @EnableConfigurationProperties(TenantProperties.class) public class YudaoTenantAutoConfiguration { + @Resource + private ApplicationContext applicationContext; + @Bean public TenantFrameworkService tenantFrameworkService(TenantApi tenantApi) { return new TenantFrameworkServiceImpl(tenantApi); @@ -67,13 +80,41 @@ public class YudaoTenantAutoConfiguration { // ========== WEB ========== @Bean - public FilterRegistrationBean tenantContextWebFilter() { + public FilterRegistrationBean tenantContextWebFilter(TenantProperties tenantProperties) { FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new TenantContextWebFilter()); registrationBean.setOrder(WebFilterOrderEnum.TENANT_CONTEXT_FILTER); + addIgnoreUrls(tenantProperties); return registrationBean; } + /** + * 如果 Controller 接口上,有 {@link TenantIgnore} 注解,那么添加到忽略的 URL 中 + * + * @param tenantProperties 租户配置 + */ + private void addIgnoreUrls(TenantProperties tenantProperties) { + // 获得接口对应的 HandlerMethod 集合 + RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) + applicationContext.getBean("requestMappingHandlerMapping"); + Map handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods(); + // 获得有 @TenantIgnore 注解的接口 + for (Map.Entry entry : handlerMethodMap.entrySet()) { + HandlerMethod handlerMethod = entry.getValue(); + if (!handlerMethod.hasMethodAnnotation(TenantIgnore.class)) { + continue; + } + // 添加到忽略的 URL 中 + if (entry.getKey().getPatternsCondition() != null) { + tenantProperties.getIgnoreUrls().addAll(entry.getKey().getPatternsCondition().getPatterns()); + } + if (entry.getKey().getPathPatternsCondition() != null) { + tenantProperties.getIgnoreUrls().addAll( + convertList(entry.getKey().getPathPatternsCondition().getPatterns(), PathPattern::getPatternString)); + } + } + } + // ========== Security ========== @Bean diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java index 927bca169e..119774b71e 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/file/FileController.java @@ -6,6 +6,7 @@ import cn.hutool.core.util.URLUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.*; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; import cn.iocoder.yudao.module.infra.service.file.FileService; @@ -76,6 +77,7 @@ public class FileController { @GetMapping("/{configId}/get/**") @PermitAll + @TenantIgnore @Operation(summary = "下载文件") @Parameter(name = "configId", description = "配置编号", required = true) public void getFileContent(HttpServletRequest request, diff --git a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/MpOpenController.java b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/MpOpenController.java index 22477b22fc..d1a1e3f510 100644 --- a/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/MpOpenController.java +++ b/yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/open/MpOpenController.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.mp.controller.admin.open; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; import cn.iocoder.yudao.module.mp.controller.admin.open.vo.MpOpenCheckSignatureReqVO; import cn.iocoder.yudao.module.mp.controller.admin.open.vo.MpOpenHandleMessageReqVO; @@ -35,26 +36,6 @@ public class MpOpenController { @Resource private MpAccountService mpAccountService; - /** - * 接收微信公众号的校验签名 - * - * 对应 文档 - */ - @Operation(summary = "校验签名") // 参见 - @GetMapping(value = "/{appId}", produces = "text/plain;charset=utf-8") - public String checkSignature(@PathVariable("appId") String appId, - MpOpenCheckSignatureReqVO reqVO) { - log.info("[checkSignature][appId({}) 接收到来自微信服务器的认证消息({})]", appId, reqVO); - // 校验请求签名 - WxMpService wxMpService = mpServiceFactory.getRequiredMpService(appId); - // 校验通过 - if (wxMpService.checkSignature(reqVO.getTimestamp(), reqVO.getNonce(), reqVO.getSignature())) { - return reqVO.getEchostr(); - } - // 校验不通过 - return "非法请求"; - } - /** * 接收微信公众号的消息推送 * @@ -62,6 +43,7 @@ public class MpOpenController { */ @Operation(summary = "处理消息") @PostMapping(value = "/{appId}", produces = "application/xml; charset=UTF-8") + @TenantIgnore public String handleMessage(@PathVariable("appId") String appId, @RequestBody String content, MpOpenHandleMessageReqVO reqVO) { @@ -79,6 +61,27 @@ public class MpOpenController { } } + /** + * 接收微信公众号的校验签名 + * + * 对应 文档 + */ + @Operation(summary = "校验签名") // 参见 + @GetMapping(value = "/{appId}", produces = "text/plain;charset=utf-8") + @TenantIgnore + public String checkSignature(@PathVariable("appId") String appId, + MpOpenCheckSignatureReqVO reqVO) { + log.info("[checkSignature][appId({}) 接收到来自微信服务器的认证消息({})]", appId, reqVO); + // 校验请求签名 + WxMpService wxMpService = mpServiceFactory.getRequiredMpService(appId); + // 校验通过 + if (wxMpService.checkSignature(reqVO.getTimestamp(), reqVO.getNonce(), reqVO.getSignature())) { + return reqVO.getEchostr(); + } + // 校验不通过 + return "非法请求"; + } + private String handleMessage0(String appId, String content, MpOpenHandleMessageReqVO reqVO) { // 校验请求签名 WxMpService mppService = mpServiceFactory.getRequiredMpService(appId); diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java index 1139a82471..9f1738ca26 100644 --- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java +++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClient; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskDetailRespVO; import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskRespVO; @@ -62,6 +63,7 @@ public class PayNotifyController { @PostMapping(value = "/order/{channelId}") @Operation(summary = "支付渠道的统一【支付】回调") @PermitAll + @TenantIgnore public String notifyOrder(@PathVariable("channelId") Long channelId, @RequestParam(required = false) Map params, @RequestBody(required = false) String body) { @@ -82,6 +84,7 @@ public class PayNotifyController { @PostMapping(value = "/refund/{channelId}") @Operation(summary = "支付渠道的统一【退款】回调") @PermitAll + @TenantIgnore public String notifyRefund(@PathVariable("channelId") Long channelId, @RequestParam(required = false) Map params, @RequestBody(required = false) String body) { @@ -102,6 +105,7 @@ public class PayNotifyController { @PostMapping(value = "/transfer/{channelId}") @Operation(summary = "支付渠道的统一【转账】回调") @PermitAll + @TenantIgnore public String notifyTransfer(@PathVariable("channelId") Long channelId, @RequestParam(required = false) Map params, @RequestBody(required = false) String body) { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java index 92259da7cf..f4e5541211 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.controller.admin.captcha; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import com.anji.captcha.model.common.ResponseModel; import com.anji.captcha.model.vo.CaptchaVO; import com.anji.captcha.service.CaptchaService; @@ -26,6 +27,7 @@ public class CaptchaController { @PostMapping({"/get"}) @Operation(summary = "获得验证码") @PermitAll + @TenantIgnore public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) { assert request.getRemoteHost() != null; data.setBrowserInfo(getRemoteId(request)); @@ -35,6 +37,7 @@ public class CaptchaController { @PostMapping("/check") @Operation(summary = "校验验证码") @PermitAll + @TenantIgnore public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) { data.setBrowserInfo(getRemoteId(request)); return captchaService.check(data); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java index 86a82537ad..7cfc3ea45f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/sms/SmsCallbackController.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.controller.admin.sms; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.system.framework.sms.core.enums.SmsChannelEnum; import cn.iocoder.yudao.module.system.service.sms.SmsSendService; import io.swagger.v3.oas.annotations.Operation; @@ -24,6 +25,7 @@ public class SmsCallbackController { @PostMapping("/aliyun") @PermitAll + @TenantIgnore @Operation(summary = "阿里云短信的回调", description = "参见 https://help.aliyun.com/document_detail/120998.html 文档") public CommonResult receiveAliyunSmsStatus(HttpServletRequest request) throws Throwable { String text = ServletUtils.getBody(request); @@ -33,6 +35,7 @@ public class SmsCallbackController { @PostMapping("/tencent") @PermitAll + @TenantIgnore @Operation(summary = "腾讯云短信的回调", description = "参见 https://cloud.tencent.com/document/product/382/52077 文档") public CommonResult receiveTencentSmsStatus(HttpServletRequest request) throws Throwable { String text = ServletUtils.getBody(request); @@ -43,6 +46,7 @@ public class SmsCallbackController { @PostMapping("/huawei") @PermitAll + @TenantIgnore @Operation(summary = "华为云短信的回调", description = "参见 https://support.huaweicloud.com/api-msgsms/sms_05_0003.html 文档") public CommonResult receiveHuaweiSmsStatus(@RequestBody String requestBody) throws Throwable { smsSendService.receiveSmsStatus(SmsChannelEnum.HUAWEI.getCode(), requestBody); @@ -51,6 +55,7 @@ public class SmsCallbackController { @PostMapping("/qiniu") @PermitAll + @TenantIgnore @Operation(summary = "七牛云短信的回调", description = "参见 https://developer.qiniu.com/sms/5910/message-push 文档") public CommonResult receiveQiniuSmsStatus(@RequestBody String requestBody) throws Throwable { smsSendService.receiveSmsStatus(SmsChannelEnum.QINIU.getCode(), requestBody); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java index f698b92d0c..8b4f5c7fa4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/tenant/TenantController.java @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantRespVO; import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantSaveReqVO; @@ -39,6 +40,7 @@ public class TenantController { @GetMapping("/get-id-by-name") @PermitAll + @TenantIgnore @Operation(summary = "使用租户名,获得租户编号", description = "登录界面,根据用户的租户名,获得租户编号") @Parameter(name = "name", description = "租户名", required = true, example = "1024") public CommonResult getTenantIdByName(@RequestParam("name") String name) { @@ -48,6 +50,7 @@ public class TenantController { @GetMapping({ "simple-list" }) @PermitAll + @TenantIgnore @Operation(summary = "获取租户精简信息列表", description = "只包含被开启的租户,用于【首页】功能的选择租户选项") public CommonResult> getTenantSimpleList() { List list = tenantService.getTenantListByStatus(CommonStatusEnum.ENABLE.getStatus()); @@ -57,6 +60,7 @@ public class TenantController { @GetMapping("/get-by-website") @PermitAll + @TenantIgnore @Operation(summary = "使用域名,获得租户信息", description = "登录界面,根据用户的域名,获得租户信息") @Parameter(name = "website", description = "域名", required = true, example = "www.iocoder.cn") public CommonResult getTenantByWebsite(@RequestParam("website") String website) { diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 1e8fdb8f9f..59307604b3 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -273,16 +273,7 @@ yudao: tenant: # 多租户相关配置项 enable: true ignore-urls: - - /admin-api/system/tenant/get-id-by-name # 基于名字获取租户,不许带租户编号 - - /admin-api/system/tenant/get-by-website # 基于域名获取租户,不许带租户编号 - - /admin-api/system/tenant/simple-list # 获取租户列表,不许带租户编号 - - /admin-api/system/captcha/get # 获取图片验证码,和租户无关 - - /admin-api/system/captcha/check # 校验图片验证码,和租户无关 - - /admin-api/infra/file/*/get/** # 获取图片,和租户无关 - - /admin-api/system/sms/callback/* # 短信回调接口,无法带上租户编号 - - /admin-api/pay/notify/** # 支付回调通知,不携带租户编号 - /jmreport/* # 积木报表,无法携带租户编号 - - /admin-api/mp/open/** # 微信公众号开放平台,微信回调接口,无法携带租户编号 ignore-tables: - system_tenant - system_tenant_package