diff --git a/backend/pom.xml b/backend/pom.xml index 9ddb0000..deb21033 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -80,7 +80,7 @@ dev info ruoyi - 123456 + HzdyjsMon@Dev#9Kx7mQ2pL @@ -94,7 +94,7 @@ prod-local warn ruoyi - 123456 + HzdyjsMon@Prod#TclhloNMWuVjq @@ -103,7 +103,7 @@ prod warn ruoyi - 123456 + HzdyjsMon@Prod#TclhloNMWuVjq diff --git a/backend/ruoyi-admin/pom.xml b/backend/ruoyi-admin/pom.xml index 78cfdea1..b396e7ab 100644 --- a/backend/ruoyi-admin/pom.xml +++ b/backend/ruoyi-admin/pom.xml @@ -80,11 +80,13 @@ ruoyi-generator - + + diff --git a/backend/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/backend/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java index 07757cb2..cab74a34 100644 --- a/backend/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java +++ b/backend/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java @@ -21,6 +21,8 @@ import org.dromara.common.core.domain.model.SocialLoginBody; import org.dromara.common.core.utils.*; import org.dromara.common.encrypt.annotation.ApiEncrypt; import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.ratelimiter.annotation.RateLimiter; +import org.dromara.common.ratelimiter.enums.LimitType; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.social.config.properties.SocialLoginConfigProperties; import org.dromara.common.social.config.properties.SocialProperties; @@ -41,6 +43,7 @@ import org.dromara.web.domain.vo.TenantListVo; import org.dromara.web.service.IAuthStrategy; import org.dromara.web.service.SysLoginService; import org.dromara.web.service.SysRegisterService; +import org.springframework.beans.factory.annotation.Value; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -73,6 +76,12 @@ public class AuthController { private final ISysClientService clientService; private final ScheduledExecutorService scheduledExecutorService; + /** + * 配置层注册总开关,默认 false(优先于数据库 sys.account.registerUser) + */ + @Value("${user.register.enabled:false}") + private boolean registerEnabled; + /** * 登录方法 * @@ -119,6 +128,7 @@ public class AuthController { @GetMapping("/binding/{source}") public R authBinding(@PathVariable("source") String source, @RequestParam("tenantId") String tenantId, @RequestParam("domain") String domain) { + loginService.checkTenant(tenantId); SocialLoginConfigProperties obj = socialProperties.getType().get(source); if (ObjectUtil.isNull(obj)) { return R.fail(source + "平台账号暂不支持"); @@ -178,11 +188,16 @@ public class AuthController { } /** - * 用户注册 + * 用户注册(免登接口;默认关闭,需同时打开配置与数据库开关) */ @ApiEncrypt + @RateLimiter(time = 60, count = 5, limitType = LimitType.IP) @PostMapping("/register") public R register(@Validated @RequestBody RegisterBody user) { + // P6:配置层硬关闭,避免仅依赖库开关被后台误开后遭滥用 + if (!registerEnabled) { + return R.fail("当前系统没有开启注册功能!"); + } // 先校验租户(含格式白名单),禁止脏 tenantId 进入 selectRegisterEnabled 触发 SQL 注入 loginService.checkTenant(user.getTenantId()); if (!configService.selectRegisterEnabled(user.getTenantId())) { diff --git a/backend/ruoyi-admin/src/main/java/org/dromara/web/controller/CasController.java b/backend/ruoyi-admin/src/main/java/org/dromara/web/controller/CasController.java index cf353ff0..fbaf5efd 100644 --- a/backend/ruoyi-admin/src/main/java/org/dromara/web/controller/CasController.java +++ b/backend/ruoyi-admin/src/main/java/org/dromara/web/controller/CasController.java @@ -68,9 +68,11 @@ public class CasController { CAS_BASE, CLIENT_ID, CLIENT_SECRET, URLEncoder.encode(code, StandardCharsets.UTF_8.toString()), REDIRECT_URI_ENCODED); - log.info("请求 CAS accessToken: {}", url); + // 禁止打印 client_secret、完整换票 URL、access_token + log.info("请求 CAS accessToken: base={}, client_id={}, codeLen={}", CAS_BASE, CLIENT_ID, + code != null ? code.length() : 0); String resp = HttpUtil.get(url); - log.info("CAS accessToken 响应: {}", resp); + log.info("CAS accessToken 响应已收到: respLen={}", resp != null ? resp.length() : 0); // 尝试解析 access_token(CAS 可能返回 JSON 或 query-string 风格) String accessToken = null; @@ -96,9 +98,10 @@ public class CasController { // 使用 access_token 请求 profile 接口 String profileUrl = String.format("%s/cas/oauth2.0/profile?access_token=%s", CAS_BASE, URLEncoder.encode(accessToken, StandardCharsets.UTF_8.toString())); - log.info("请求 CAS profile: {}", profileUrl); + // 禁止打印 access_token 与完整 profile + log.info("请求 CAS profile: base={}", CAS_BASE); String profileResp = HttpUtil.get(profileUrl); - log.info("CAS profile 响应: {}", profileResp); + log.info("CAS profile 响应已收到: respLen={}", profileResp != null ? profileResp.length() : 0); // 解析 profile,尝试从 attributes 中找到 CODE(用户名) 和 TENANTID try { @@ -178,7 +181,7 @@ public class CasController { return R.fail("处理 CAS profile 失败: " + e.getMessage()); } } else { - return R.fail("无法解析 CAS access_token,原始响应: " + resp); + return R.fail("无法解析 CAS access_token"); } } catch (Exception e) { log.error("请求 CAS accessToken 失败", e); diff --git a/backend/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/backend/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java index 7726ec52..84b52845 100644 --- a/backend/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java +++ b/backend/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java @@ -225,14 +225,16 @@ public class SysLoginService { * @param tenantId 租户ID */ public void checkTenant(String tenantId) { + // 只要传入了 tenantId,无论租户开关是否开启都先做格式白名单(防注入) + if (StringUtils.isNotBlank(tenantId)) { + TenantHelper.checkTenantIdFormat(tenantId); + } if (!TenantHelper.isEnable()) { return; } if (StringUtils.isBlank(tenantId)) { throw new TenantException("tenant.number.not.blank"); } - // 格式白名单,阻断恶意 tenantId 进入后续查询/动态租户 - TenantHelper.checkTenantIdFormat(tenantId); if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { return; } diff --git a/backend/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java b/backend/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java index 567906e4..9bb00f0c 100644 --- a/backend/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java +++ b/backend/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java @@ -22,6 +22,7 @@ import org.dromara.system.domain.SysUser; import org.dromara.system.domain.bo.SysUserBo; import org.dromara.system.mapper.SysUserMapper; import org.dromara.system.service.ISysUserService; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; /** @@ -37,11 +38,19 @@ public class SysRegisterService { private final SysUserMapper userMapper; private final CaptchaProperties captchaProperties; + @Value("${user.register.enabled:false}") + private boolean registerEnabled; + /** * 注册 */ public void register(RegisterBody registerBody) { + if (!registerEnabled) { + throw new UserException("user.register.disabled"); + } String tenantId = registerBody.getTenantId(); + // 动态租户查询前校验格式,防止绕过 Controller 时注入 + TenantHelper.checkTenantIdFormat(tenantId); String username = registerBody.getUsername(); String password = registerBody.getPassword(); // 校验用户类型是否存在 diff --git a/backend/ruoyi-admin/src/main/resources/application-dev.yml b/backend/ruoyi-admin/src/main/resources/application-dev.yml index 96b88da6..9eb434d4 100644 --- a/backend/ruoyi-admin/src/main/resources/application-dev.yml +++ b/backend/ruoyi-admin/src/main/resources/application-dev.yml @@ -1,7 +1,19 @@ ---- # 监控中心配置 +--- # Actuator 全关(不使用) +management: + endpoints: + enabled-by-default: false + web: + exposure: + include: "" + endpoint: + health: + enabled: false + heapdump: + enabled: false + +--- # 监控中心配置(不使用,关闭客户端) spring.boot.admin.client: - # 增加客户端开关 - enabled: true + enabled: false url: http://localhost:9090/admin instance: service-host-type: IP @@ -74,8 +86,8 @@ spring: # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) # 增加锁等待超时参数,减少锁冲突 url: jdbc:mysql://47.99.164.66:3306/hzdyjs_xg?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&innodb_lock_wait_timeout=120&autocommit=true - username: root - password: hn02le.34lkdLKD + username: hzdyjs_app + password: Hzdyjs@App#n4SQi8AfPHldNj49 # # 从库数据源 # slave: # lazy: true @@ -130,7 +142,7 @@ spring.data: # 数据库索引 database: 8 # redis 密码必须配置 - password: Hzdyjs@123456 + password: "Fwd7y-8UDlZ3%3VO8kwn%J1T" # 连接超时时间 timeout: 30s # 是否开启ssl diff --git a/backend/ruoyi-admin/src/main/resources/application-prod-68-9900.yml b/backend/ruoyi-admin/src/main/resources/application-prod-68-9900.yml index ce2ca0b3..f4f89141 100644 --- a/backend/ruoyi-admin/src/main/resources/application-prod-68-9900.yml +++ b/backend/ruoyi-admin/src/main/resources/application-prod-68-9900.yml @@ -18,7 +18,7 @@ logging: # 监控中心配置 - 端口漂移 spring.boot.admin.client: - enabled: true + enabled: false url: http://172.16.0.67:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-admin/src/main/resources/application-prod-68-9901.yml b/backend/ruoyi-admin/src/main/resources/application-prod-68-9901.yml index d6a7e796..a3f587e0 100644 --- a/backend/ruoyi-admin/src/main/resources/application-prod-68-9901.yml +++ b/backend/ruoyi-admin/src/main/resources/application-prod-68-9901.yml @@ -18,7 +18,7 @@ logging: # 监控中心配置 - 端口漂移 spring.boot.admin.client: - enabled: true + enabled: false url: http://172.16.0.67:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-admin/src/main/resources/application-prod-68-9902.yml b/backend/ruoyi-admin/src/main/resources/application-prod-68-9902.yml index aa1e62dd..ebbb6161 100644 --- a/backend/ruoyi-admin/src/main/resources/application-prod-68-9902.yml +++ b/backend/ruoyi-admin/src/main/resources/application-prod-68-9902.yml @@ -18,7 +18,7 @@ logging: # 监控中心配置 - 端口漂移 spring.boot.admin.client: - enabled: true + enabled: false url: http://172.16.0.67:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-admin/src/main/resources/application-prod-68-9903.yml b/backend/ruoyi-admin/src/main/resources/application-prod-68-9903.yml index 66a7084e..b2bfea0d 100644 --- a/backend/ruoyi-admin/src/main/resources/application-prod-68-9903.yml +++ b/backend/ruoyi-admin/src/main/resources/application-prod-68-9903.yml @@ -18,7 +18,7 @@ logging: # 监控中心配置 - 端口漂移 spring.boot.admin.client: - enabled: true + enabled: false url: http://172.16.0.67:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-admin/src/main/resources/application-prod-9900.yml b/backend/ruoyi-admin/src/main/resources/application-prod-9900.yml index a0648192..f4034898 100644 --- a/backend/ruoyi-admin/src/main/resources/application-prod-9900.yml +++ b/backend/ruoyi-admin/src/main/resources/application-prod-9900.yml @@ -18,7 +18,7 @@ logging: # 监控中心配置 - 端口漂移 spring.boot.admin.client: - enabled: true + enabled: false url: http://172.16.0.67:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-admin/src/main/resources/application-prod-9901.yml b/backend/ruoyi-admin/src/main/resources/application-prod-9901.yml index 699e3d3c..6477c194 100644 --- a/backend/ruoyi-admin/src/main/resources/application-prod-9901.yml +++ b/backend/ruoyi-admin/src/main/resources/application-prod-9901.yml @@ -18,7 +18,7 @@ logging: # 监控中心配置 - 端口漂移 spring.boot.admin.client: - enabled: true + enabled: false url: http://172.16.0.67:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-admin/src/main/resources/application-prod-9902.yml b/backend/ruoyi-admin/src/main/resources/application-prod-9902.yml index c50e9f94..f8f87ca0 100644 --- a/backend/ruoyi-admin/src/main/resources/application-prod-9902.yml +++ b/backend/ruoyi-admin/src/main/resources/application-prod-9902.yml @@ -18,7 +18,7 @@ logging: # 监控中心配置 - 端口漂移 spring.boot.admin.client: - enabled: true + enabled: false url: http://172.16.0.67:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-admin/src/main/resources/application-prod-9903.yml b/backend/ruoyi-admin/src/main/resources/application-prod-9903.yml index 209ae9a6..de55fc48 100644 --- a/backend/ruoyi-admin/src/main/resources/application-prod-9903.yml +++ b/backend/ruoyi-admin/src/main/resources/application-prod-9903.yml @@ -18,7 +18,7 @@ logging: # 监控中心配置 - 端口漂移 spring.boot.admin.client: - enabled: true + enabled: false url: http://172.16.0.67:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-admin/src/main/resources/application-prod-local.yml b/backend/ruoyi-admin/src/main/resources/application-prod-local.yml index 7ba1abbf..996eef7e 100644 --- a/backend/ruoyi-admin/src/main/resources/application-prod-local.yml +++ b/backend/ruoyi-admin/src/main/resources/application-prod-local.yml @@ -1,10 +1,22 @@ --- # 临时文件存储位置 避免临时文件被系统清理报错 spring.servlet.multipart.location: /ruoyi/server/temp ---- # 监控中心配置 +--- # Actuator 全关(不使用) +management: + endpoints: + enabled-by-default: false + web: + exposure: + include: "" + endpoint: + health: + enabled: false + heapdump: + enabled: false + +--- # 监控中心配置(不使用,关闭客户端) spring.boot.admin.client: - # 增加客户端开关 - enabled: true + enabled: false url: http://47.121.125.41:9090/admin instance: service-host-type: IP @@ -53,8 +65,8 @@ spring: # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) url: jdbc:mysql://47.99.164.66:3306/hzdyjs_xg?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true - username: root - password: hn02le.34lkdLKD + username: hzdyjs_app + password: Hzdyjs@App#n4SQi8AfPHldNj49 # # 从库数据源 # slave: # lazy: true @@ -107,7 +119,7 @@ spring.data: # 数据库索引 database: 3 # redis 密码必须配置 - password: Hzdyjs@123456 + password: "Fwd7y-8UDlZ3%3VO8kwn%J1T" # 连接超时时间 timeout: 10s # 是否开启ssl diff --git a/backend/ruoyi-admin/src/main/resources/application-prod.yml b/backend/ruoyi-admin/src/main/resources/application-prod.yml index c16b8817..2f8daf65 100644 --- a/backend/ruoyi-admin/src/main/resources/application-prod.yml +++ b/backend/ruoyi-admin/src/main/resources/application-prod.yml @@ -1,10 +1,22 @@ --- # 临时文件存储位置 避免临时文件被系统清理报错 spring.servlet.multipart.location: /ruoyi/server/temp ---- # 监控中心配置 +--- # Actuator 全关(不使用) +management: + endpoints: + enabled-by-default: false + web: + exposure: + include: "" + endpoint: + health: + enabled: false + heapdump: + enabled: false + +--- # 监控中心配置(不使用,关闭客户端) spring.boot.admin.client: - # 增加客户端开关 - enabled: true + enabled: false url: http://172.16.0.67:9090/admin instance: service-host-type: IP @@ -53,8 +65,8 @@ spring: # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) url: jdbc:mysql://172.16.0.67:3306/hzdyjs_xg?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true - username: root - password: Hzdyjs@Root@123456 + username: hzdyjs_app + password: Hzdyjs@App#n4SQi8AfPHldNj49 # # 从库数据源 # slave: # lazy: true diff --git a/backend/ruoyi-admin/src/main/resources/application.yml b/backend/ruoyi-admin/src/main/resources/application.yml index dab61975..9485988d 100644 --- a/backend/ruoyi-admin/src/main/resources/application.yml +++ b/backend/ruoyi-admin/src/main/resources/application.yml @@ -58,6 +58,9 @@ logging: # 用户配置 user: + # 开放注册总开关(P6:校园场景默认关闭,防止免登 /auth/register 被滥用) + register: + enabled: false password: # 密码最大错误次数 maxRetryCount: 5 @@ -125,7 +128,7 @@ sa-token: # security配置 security: - # 排除路径 + # 排除路径(P0:已下线 Swagger/api-docs,不再加入白名单) excludes: - /*.html - /**/*.html @@ -133,20 +136,10 @@ security: - /**/*.js - /favicon.ico - /error - - /*/api-docs - - /*/api-docs/** - - /api-docs - - /api-docs/** - - /swagger-ui/** - - /swagger-ui.html - - /swagger-ui/index.html - - /v3/api-docs/** - - /webjars/** - /warm-flow-ui/config # 招聘门户公开接口 weizhong - /rs/job/public/** - /rs/job/view/** - - /rs/application/submit - /system/dict/data/type/* # 多租户配置 @@ -216,50 +209,25 @@ api-decrypt: # 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= +# P0:Swagger / api-docs 已下线,禁止对外暴露接口清单 springdoc: api-docs: - # 是否开启接口文档 - enabled: true - # 接口文档路径 + enabled: false path: /api-docs swagger-ui: - # 启用 Swagger UI - enabled: true - # Swagger UI 路径 + enabled: false path: /swagger-ui.html info: - # 标题 title: '标题:杭州第一技师学院智慧校园管理系统_接口文档' - # 描述 - description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...' - # 版本 + description: '描述:接口文档已关闭' version: '版本号: ${ruoyi.version}' - # 作者信息 - contact: - name: Lion Li - email: crazylionli@163.com - url: https://gitee.com/dromara/RuoYi-Vue-Plus components: - # 鉴权方式配置 security-schemes: apiKey: type: APIKEY in: HEADER name: ${sa-token.token-name} - #这里定义了两个分组,可定义多个,也可以不定义 - group-configs: - - group: 1.演示模块 - packages-to-scan: org.dromara.demo - - group: 2.通用模块 - packages-to-scan: org.dromara.web - - group: 3.系统模块 - packages-to-scan: org.dromara.system - - group: 4.代码生成模块 - packages-to-scan: org.dromara.generator - - group: 5.工作流模块 - packages-to-scan: org.dromara.workflow - - group: 6.所有业务模块 - packages-to-scan: org.dromara + group-configs: [] # 防止XSS攻击 xss: @@ -286,15 +254,18 @@ lock4j: # 分布式锁的超时时间,默认为 30 秒 expire: 30000 ---- # Actuator 监控端点的配置项 +--- # Actuator:不使用监控,关闭全部 Web 端点(含 heapdump) management: endpoints: + enabled-by-default: false web: exposure: - include: '*' + include: "" endpoint: health: - show-details: ALWAYS + enabled: false + heapdump: + enabled: false logfile: external-file: ./logs/sys-console.log diff --git a/backend/ruoyi-admin/src/main/resources/i18n/messages.properties b/backend/ruoyi-admin/src/main/resources/i18n/messages.properties index 06c5b642..2941bb77 100644 --- a/backend/ruoyi-admin/src/main/resources/i18n/messages.properties +++ b/backend/ruoyi-admin/src/main/resources/i18n/messages.properties @@ -25,6 +25,7 @@ user.login.success=登录成功 user.register.success=注册成功 user.register.save.error=保存用户 {0} 失败,注册账号已存在 user.register.error=注册失败,请联系系统管理人员 +user.register.disabled=当前系统没有开启注册功能! user.notfound=请重新登录 user.forcelogout=管理员强制退出,请重新登录 user.unknown.error=未知错误,请重新登录 diff --git a/backend/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/backend/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties index db3c8669..12df9b46 100644 --- a/backend/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties +++ b/backend/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties @@ -25,6 +25,7 @@ user.login.success=Login successful user.register.success=Register successful user.register.save.error=Failed to save user {0}, The registered account already exists user.register.error=Register failed, please contact system administrator +user.register.disabled=User registration is disabled user.notfound=Please login again user.forcelogout=The administrator is forced to exit,please login again user.unknown.error=Unknown error, please login again diff --git a/backend/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/backend/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties index 06c5b642..2941bb77 100644 --- a/backend/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties +++ b/backend/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties @@ -25,6 +25,7 @@ user.login.success=登录成功 user.register.success=注册成功 user.register.save.error=保存用户 {0} 失败,注册账号已存在 user.register.error=注册失败,请联系系统管理人员 +user.register.disabled=当前系统没有开启注册功能! user.notfound=请重新登录 user.forcelogout=管理员强制退出,请重新登录 user.unknown.error=未知错误,请重新登录 diff --git a/backend/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java b/backend/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java index d9f70e42..dee1f19b 100644 --- a/backend/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java +++ b/backend/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java @@ -3,6 +3,7 @@ package org.dromara.common.core.config; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; /** * 程序注解配置 @@ -12,6 +13,7 @@ import org.springframework.scheduling.annotation.EnableAsync; @AutoConfiguration @EnableAspectJAutoProxy @EnableAsync(proxyTargetClass = true) +@EnableScheduling public class ApplicationConfig { } diff --git a/backend/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java b/backend/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java index 63bee0dd..6bcb9f1e 100644 --- a/backend/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java +++ b/backend/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java @@ -1,6 +1,7 @@ package org.dromara.common.core.domain.model; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; import lombok.Data; import java.io.Serial; @@ -31,8 +32,9 @@ public class LoginBody implements Serializable { private String grantType; /** - * 租户ID + * 租户ID(仅允许纯数字,防止拼进 SQL 导致注入) */ + @Pattern(regexp = "^[0-9]{1,20}$", message = "{tenant.id.invalid}") private String tenantId; /** diff --git a/backend/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java b/backend/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java index cba37534..35dfd97a 100644 --- a/backend/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java +++ b/backend/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java @@ -10,17 +10,16 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.EnableScheduling; /** - * 启动定时任务 + * 启动 SnailJob 客户端 + *

Spring {@code @Scheduled} 已由 {@code ApplicationConfig} 统一开启,不再依赖本配置。

* * @author opensnail * @date 2024-05-17 */ @AutoConfiguration @ConditionalOnProperty(prefix = "snail-job", name = "enabled", havingValue = "true") -@EnableScheduling @EnableSnailJob public class SnailJobConfig { diff --git a/backend/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java b/backend/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java index df524b28..b687ad9d 100644 --- a/backend/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java +++ b/backend/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java @@ -160,11 +160,13 @@ public class TenantHelper { * @param global 是否全局生效 */ public static void setDynamic(String tenantId, boolean global) { + // 传入非空时一律先校验格式,避免租户开关关闭时仍把脏数据带入后续逻辑 + if (StringUtils.isNotBlank(tenantId)) { + checkTenantIdFormat(tenantId); + } if (!isEnable()) { return; } - // 动态租户一律做格式白名单校验,覆盖 login/register/config 等所有 TenantHelper.dynamic 入口 - checkTenantIdFormat(tenantId); if (!LoginHelper.isLogin() || !global) { TEMP_DYNAMIC_TENANT.set(tenantId); return; diff --git a/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod-local.yml b/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod-local.yml index fdfc034f..fa4c91d4 100644 --- a/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod-local.yml +++ b/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod-local.yml @@ -21,22 +21,25 @@ spring: title: RuoYi-Vue-Plus服务监控中心 context-path: /admin ---- # Actuator 监控端点的配置项 +--- # Actuator 全关(不使用) management: endpoints: + enabled-by-default: false web: exposure: - include: '*' + include: "" endpoint: health: - show-details: ALWAYS + enabled: false + heapdump: + enabled: false logfile: external-file: ./logs/ruoyi-monitor-admin.log --- # 监控配置 spring.boot.admin.client: # 增加客户端开关 - enabled: true + enabled: false # 设置 Spring Boot Admin Server 地址 url: http://47.121.125.41:9090/admin instance: diff --git a/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml b/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml index 019f80d8..752c8ee2 100644 --- a/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml +++ b/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml @@ -23,22 +23,25 @@ spring: # 配置公网访问地址,确保重定向和静态资源路径包含正确的端口号 # public-url: http://web.hzdyjsxy.cn:18081/admin ---- # Actuator 监控端点的配置项 +--- # Actuator 全关(不使用) management: endpoints: + enabled-by-default: false web: exposure: - include: '*' + include: "" endpoint: health: - show-details: ALWAYS + enabled: false + heapdump: + enabled: false logfile: external-file: ./logs/ruoyi-monitor-admin.log --- # 监控配置 spring.boot.admin.client: # 增加客户端开关 - enabled: true + enabled: false # 设置 Spring Boot Admin Server 地址 url: http://172.16.0.67:9090/admin instance: diff --git a/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml b/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml index 86766d7a..1cbe8a4b 100644 --- a/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml +++ b/backend/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml @@ -21,22 +21,25 @@ spring: title: RuoYi-Vue-Plus服务监控中心 context-path: /admin ---- # Actuator 监控端点的配置项 +--- # Actuator 全关(不使用) management: endpoints: + enabled-by-default: false web: exposure: - include: '*' + include: "" endpoint: health: - show-details: ALWAYS + enabled: false + heapdump: + enabled: false logfile: external-file: ./logs/ruoyi-monitor-admin.log --- # 监控配置 spring.boot.admin.client: # 增加客户端开关 - enabled: true + enabled: false # 设置 Spring Boot Admin Server 地址 url: http://127.0.0.1:9090/admin instance: diff --git a/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml b/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml index 5dd063ff..bebce895 100644 --- a/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml +++ b/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml @@ -3,8 +3,8 @@ spring: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://47.99.164.66:3306/hzdyjs_xg?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true - username: root - password: hn02le.34lkdLKD + username: hzdyjs_app + password: Hzdyjs@App#n4SQi8AfPHldNj49 hikari: connection-timeout: 30000 validation-timeout: 5000 @@ -29,7 +29,7 @@ snail-job: --- # 监控中心配置 spring.boot.admin.client: # 增加客户端开关 - enabled: true + enabled: false url: http://localhost:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod-local.yml b/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod-local.yml index 0f731ab7..9e949361 100644 --- a/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod-local.yml +++ b/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod-local.yml @@ -3,8 +3,8 @@ spring: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://47.99.164.66:3306/hzdyjs_xg?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true - username: root - password: hn02le.34lkdLKD + username: hzdyjs_app + password: Hzdyjs@App#n4SQi8AfPHldNj49 hikari: connection-timeout: 30000 validation-timeout: 5000 @@ -29,7 +29,7 @@ snail-job: --- # 监控中心配置 spring.boot.admin.client: # 增加客户端开关 - enabled: true + enabled: false url: http://47.121.125.41:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml b/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml index a0059e7d..414e91b9 100644 --- a/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml +++ b/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml @@ -3,8 +3,8 @@ spring: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://172.16.0.67:3306/hzdyjs_xg?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true - username: root - password: Hzdyjs@Root@123456 + username: hzdyjs_app + password: Hzdyjs@App#n4SQi8AfPHldNj49 hikari: connection-timeout: 30000 validation-timeout: 5000 @@ -29,7 +29,7 @@ snail-job: --- # 监控中心配置 spring.boot.admin.client: # 增加客户端开关 - enabled: true + enabled: false url: http://172.16.0.67:9090/admin instance: service-host-type: IP diff --git a/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application.yml b/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application.yml index ba6df45f..8c019805 100644 --- a/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application.yml +++ b/backend/ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application.yml @@ -29,11 +29,14 @@ logging: management: endpoints: + enabled-by-default: false web: exposure: - include: '*' + include: "" endpoint: health: - show-details: ALWAYS + enabled: false + heapdump: + enabled: false logfile: external-file: ./logs/ruoyi-snailjob-server/console.log diff --git a/backend/ruoyi-modules/ruoyi-aqbw/pom.xml b/backend/ruoyi-modules/ruoyi-aqbw/pom.xml index 10119be5..ab382f80 100644 --- a/backend/ruoyi-modules/ruoyi-aqbw/pom.xml +++ b/backend/ruoyi-modules/ruoyi-aqbw/pom.xml @@ -92,11 +92,13 @@ ruoyi-generator
- + + diff --git a/backend/ruoyi-modules/ruoyi-bzrkh/pom.xml b/backend/ruoyi-modules/ruoyi-bzrkh/pom.xml index e903bcff..e83ae7a2 100644 --- a/backend/ruoyi-modules/ruoyi-bzrkh/pom.xml +++ b/backend/ruoyi-modules/ruoyi-bzrkh/pom.xml @@ -92,11 +92,13 @@ ruoyi-generator - + + diff --git a/backend/ruoyi-modules/ruoyi-cw/pom.xml b/backend/ruoyi-modules/ruoyi-cw/pom.xml index 4c32e285..a8950c39 100644 --- a/backend/ruoyi-modules/ruoyi-cw/pom.xml +++ b/backend/ruoyi-modules/ruoyi-cw/pom.xml @@ -92,11 +92,13 @@ ruoyi-generator - + + diff --git a/backend/ruoyi-modules/ruoyi-hq/pom.xml b/backend/ruoyi-modules/ruoyi-hq/pom.xml index 3c07544d..e413e8b5 100644 --- a/backend/ruoyi-modules/ruoyi-hq/pom.xml +++ b/backend/ruoyi-modules/ruoyi-hq/pom.xml @@ -92,11 +92,13 @@ ruoyi-generator - + + diff --git a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/IHqSatSurveyService.java b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/IHqSatSurveyService.java index 68703d50..cdf37e40 100644 --- a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/IHqSatSurveyService.java +++ b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/IHqSatSurveyService.java @@ -174,4 +174,11 @@ public interface IHqSatSurveyService { * @param response HTTP响应 */ void exportSurveyRawData(Long surveyId, jakarta.servlet.http.HttpServletResponse response); + + /** + * 将已过期问卷状态更新为已结束(status=2) + * + * @return 更新条数 + */ + int updateExpiredSurveys(); } diff --git a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/impl/HqSatSurveyServiceImpl.java b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/impl/HqSatSurveyServiceImpl.java index 92e86169..a005eda8 100644 --- a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/impl/HqSatSurveyServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/service/impl/HqSatSurveyServiceImpl.java @@ -6,7 +6,9 @@ import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.PageQuery; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.dromara.common.tenant.helper.TenantHelper; import cn.hutool.core.collection.CollUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -1741,4 +1743,21 @@ public class HqSatSurveyServiceImpl implements IHqSatSurveyService { public java.util.List> getAnswers() { return answers; } public void setAnswers(java.util.List> answers) { this.answers = answers; } } + + /** + * 将 end_time 已过期且未结束的问卷标记为已结束。 + * 定时任务无登录上下文,需忽略租户插件,覆盖全部租户。 + */ + @Override + public int updateExpiredSurveys() { + Date now = new Date(); + return TenantHelper.ignore(() -> { + LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate(); + updateWrapper.set(HqSatSurvey::getStatus, "2") + .set(HqSatSurvey::getUpdateTime, now) + .lt(HqSatSurvey::getEndTime, now) + .ne(HqSatSurvey::getStatus, "2"); + return baseMapper.update(null, updateWrapper); + }); + } } diff --git a/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/task/HqSatSurveyExpireTask.java b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/task/HqSatSurveyExpireTask.java new file mode 100644 index 00000000..4b6bc725 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-hq/src/main/java/org/dromara/hq/task/HqSatSurveyExpireTask.java @@ -0,0 +1,46 @@ +package org.dromara.hq.task; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.hq.service.IHqSatSurveyService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +/** + * 满意度调查问卷过期扫描任务 + *

替代原 SnailJob surveyEndTimeJobExecutor:每小时将 end_time 已过期的问卷 status 更新为 2(已结束)。

+ */ +@Slf4j +@Component +@RequiredArgsConstructor +public class HqSatSurveyExpireTask { + + private static final String LOCK_KEY = "hq:sat:survey:expire:lock"; + private static final Duration LOCK_TTL = Duration.ofMinutes(10); + + private final IHqSatSurveyService satSurveyService; + + /** + * 每小时整点执行(与原 SnailJob 3600 秒间隔对齐) + */ + @Scheduled(cron = "0 0 * * * ?") + public void updateExpiredSurveys() { + boolean locked = RedisUtils.setObjectIfAbsent(LOCK_KEY, "1", LOCK_TTL); + if (!locked) { + log.debug("满意度调查过期扫描跳过:其他实例正在执行"); + return; + } + try { + log.info("开始执行满意度调查过期扫描"); + int updatedCount = satSurveyService.updateExpiredSurveys(); + log.info("满意度调查过期扫描完成,更新数量: {}", updatedCount); + } catch (Exception e) { + log.error("满意度调查过期扫描失败", e); + } finally { + RedisUtils.deleteObject(LOCK_KEY); + } + } +} diff --git a/backend/ruoyi-modules/ruoyi-jcbt/pom.xml b/backend/ruoyi-modules/ruoyi-jcbt/pom.xml index d294f710..b0e6f5e5 100644 --- a/backend/ruoyi-modules/ruoyi-jcbt/pom.xml +++ b/backend/ruoyi-modules/ruoyi-jcbt/pom.xml @@ -92,11 +92,13 @@ ruoyi-generator
- + + diff --git a/backend/ruoyi-modules/ruoyi-job/pom.xml b/backend/ruoyi-modules/ruoyi-job/pom.xml index e81b66e4..48ee0df8 100644 --- a/backend/ruoyi-modules/ruoyi-job/pom.xml +++ b/backend/ruoyi-modules/ruoyi-job/pom.xml @@ -27,12 +27,6 @@ ruoyi-common-job - - - org.springframework - spring-jdbc - - diff --git a/backend/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/SurveyEndTimeJobExecutor.java b/backend/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/SurveyEndTimeJobExecutor.java deleted file mode 100644 index a306f43f..00000000 --- a/backend/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/SurveyEndTimeJobExecutor.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.dromara.job.snailjob; - -import com.aizuda.snailjob.client.job.core.annotation.JobExecutor; -import com.aizuda.snailjob.client.job.core.dto.JobArgs; -import com.aizuda.snailjob.client.model.ExecuteResult; -import com.aizuda.snailjob.common.core.util.JsonUtil; -import com.aizuda.snailjob.common.log.SnailJobLog; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -/** - * 满意度调查问卷结束时间扫描任务 - * 扫描hq_sat_survey表,检查end_time是否已小于当前时间 - * 若已过期,则将状态(status)更新为2 - */ -@Component -@JobExecutor(name = "surveyEndTimeJobExecutor") -public class SurveyEndTimeJobExecutor { - - @Autowired - private SurveyJobService surveyJobService; - - public ExecuteResult jobExecute(JobArgs jobArgs) { - SnailJobLog.LOCAL.info("surveyEndTimeJobExecutor start. jobArgs:{}", JsonUtil.toJsonString(jobArgs)); - SnailJobLog.REMOTE.info("surveyEndTimeJobExecutor start. jobArgs:{}", JsonUtil.toJsonString(jobArgs)); - - try { - // 执行扫描和状态更新 - int updatedCount = surveyJobService.updateExpiredSurveys(); - - String resultMsg = "满意度调查过期状态更新完成,更新数量: " + updatedCount; - SnailJobLog.LOCAL.info(resultMsg); - SnailJobLog.REMOTE.info(resultMsg); - - return ExecuteResult.success(resultMsg); - } catch (Exception e) { - String errorMsg = "满意度调查过期状态更新失败: " + e.getMessage(); - SnailJobLog.LOCAL.error(errorMsg, e); - SnailJobLog.REMOTE.error(errorMsg, e); - - return ExecuteResult.failure(errorMsg); - } - } -} diff --git a/backend/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/SurveyJobService.java b/backend/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/SurveyJobService.java deleted file mode 100644 index 2d15de14..00000000 --- a/backend/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/SurveyJobService.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.dromara.job.snailjob; - -import org.dromara.common.core.enums.FormatsType; -import org.dromara.common.core.utils.DateUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Date; - -/** - * 满意度调查问卷结束时间扫描服务 - * 提供扫描过期调查问卷并更新状态的功能 - */ -@Service -public class SurveyJobService { - - /** - * 满意度调查问卷表名 - */ - private static final String TABLE_NAME = "hq_sat_survey"; - - /** - * 已结束状态值 - */ - private static final int STATUS_ENDED = 2; - - @Autowired - private JdbcTemplate jdbcTemplate; - - /** - * 更新过期的满意度调查问卷状态 - * 检查end_time小于当前时间的记录,将status更新为2 - * - * @return 更新的记录数 - */ - @Transactional(rollbackFor = Exception.class) - public int updateExpiredSurveys() { - Date now = DateUtils.getNowDate(); - - // 构建更新SQL - String updateSql = "UPDATE " + TABLE_NAME + - " SET status = ?, update_time = ? " + - " WHERE end_time < ? AND status != ? AND deleted = 0"; - - // 执行更新并返回更新的记录数 - return jdbcTemplate.update( - updateSql, - STATUS_ENDED, - DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, now), - DateUtils.parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, now), - STATUS_ENDED - ); - } -} diff --git a/backend/ruoyi-modules/ruoyi-rs/pom.xml b/backend/ruoyi-modules/ruoyi-rs/pom.xml index 2d6e79c6..2eb28833 100644 --- a/backend/ruoyi-modules/ruoyi-rs/pom.xml +++ b/backend/ruoyi-modules/ruoyi-rs/pom.xml @@ -92,11 +92,13 @@ ruoyi-generator - + + diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsApplicationController.java b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsApplicationController.java index 4631d49b..420fc14c 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsApplicationController.java +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsApplicationController.java @@ -24,8 +24,8 @@ import org.dromara.common.core.utils.DateUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.exception.ServiceException; import cn.dev33.satoken.annotation.SaCheckPermission; -import cn.dev33.satoken.annotation.SaIgnore; import jakarta.servlet.http.HttpServletResponse; +import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.rs.domain.RsApplication; import org.dromara.rs.service.IRsApplicationService; @@ -292,9 +292,8 @@ public class RsApplicationController extends BaseController { } /** - * 提交应聘申请(公开接口) + * 提交应聘申请(须登录) */ - @SaIgnore @Log(title = "提交应聘申请", businessType = BusinessType.INSERT) @PostMapping("/submit") public R> submitApplication(@RequestBody RsApplication application) { @@ -307,9 +306,8 @@ public class RsApplicationController extends BaseController { // 设置申请时间 application.setApplyTime(new java.util.Date()); - // 对于匿名用户,applicant_id 设置为 null - // 如果将来需要支持已登录用户,可以从 token 中获取用户ID - application.setApplicantId(null); + // 绑定当前登录用户 + application.setApplicantId(LoginHelper.getUserId()); // 根据jobId设置职位标题 if (application.getJobId() != null) { diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsInitController.java b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsInitController.java index bfa6cbd2..f8912879 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsInitController.java +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsInitController.java @@ -12,7 +12,7 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import cn.dev33.satoken.annotation.SaIgnore; +import cn.dev33.satoken.annotation.SaCheckPermission; /** * 人事管理初始化控制器 @@ -116,9 +116,9 @@ public class RsInitController extends BaseController { } /** - * 更新菜单数据(不需要认证) + * 更新菜单数据(须登录且具备菜单编辑权限) */ - @SaIgnore + @SaCheckPermission("system:menu:edit") @PostMapping("/update-menu") @Log(title = "更新人事管理菜单", businessType = BusinessType.UPDATE) public R updateMenu() { diff --git a/backend/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java b/backend/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java index d92647c4..e48cfaf4 100644 --- a/backend/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java @@ -83,6 +83,8 @@ public class SysConfigServiceImpl implements ISysConfigService, ConfigService { */ @Override public boolean selectRegisterEnabled(String tenantId) { + // 防御纵深:动态租户查询前再次校验,避免绕过 Controller 时注入 + TenantHelper.checkTenantIdFormat(tenantId); SysConfig retConfig = TenantHelper.dynamic(tenantId, () -> { return baseMapper.selectOne(new LambdaQueryWrapper() .eq(SysConfig::getConfigKey, "sys.account.registerUser")); diff --git a/backend/ruoyi-modules/ruoyi-xg/pom.xml b/backend/ruoyi-modules/ruoyi-xg/pom.xml index a2987fb7..3b47f0fb 100644 --- a/backend/ruoyi-modules/ruoyi-xg/pom.xml +++ b/backend/ruoyi-modules/ruoyi-xg/pom.xml @@ -92,11 +92,13 @@ ruoyi-generator - + + diff --git a/backend/ruoyi-modules/ruoyi-xskh/pom.xml b/backend/ruoyi-modules/ruoyi-xskh/pom.xml index c3ac3338..3215f0f0 100644 --- a/backend/ruoyi-modules/ruoyi-xskh/pom.xml +++ b/backend/ruoyi-modules/ruoyi-xskh/pom.xml @@ -92,11 +92,13 @@ ruoyi-generator - + + diff --git a/backend/ruoyi-modules/ruoyi-zsjy/pom.xml b/backend/ruoyi-modules/ruoyi-zsjy/pom.xml index 9fbea31f..402b2df8 100644 --- a/backend/ruoyi-modules/ruoyi-zsjy/pom.xml +++ b/backend/ruoyi-modules/ruoyi-zsjy/pom.xml @@ -92,11 +92,13 @@ ruoyi-generator - + + diff --git a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/ZsjyEnrollmentInfoController.java b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/ZsjyEnrollmentInfoController.java index 8ec995be..4fa5262a 100644 --- a/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/ZsjyEnrollmentInfoController.java +++ b/backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/ZsjyEnrollmentInfoController.java @@ -7,7 +7,6 @@ import lombok.RequiredArgsConstructor; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; -import cn.dev33.satoken.annotation.SaIgnore; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; import org.dromara.common.idempotent.annotation.RepeatSubmit; @@ -103,9 +102,8 @@ public class ZsjyEnrollmentInfoController extends BaseController { } /** - * 根据身份证号和准考证号查询报名信息 + * 根据身份证号和准考证号查询报名信息(须登录) */ - @SaIgnore @GetMapping("/query") public R queryByIdCardAndExamNumber( @RequestParam(value = "idCard", required = false) String idCard, @@ -115,9 +113,8 @@ public class ZsjyEnrollmentInfoController extends BaseController { } /** - * 提交报名信息(供学生端使用) + * 提交报名信息(供学生端使用,须登录) */ - @SaIgnore @Log(title = "学生报名", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping("/submit") @@ -126,9 +123,8 @@ public class ZsjyEnrollmentInfoController extends BaseController { } /** - * 查询我的报名状态(供学生端使用) + * 查询我的报名状态(供学生端使用,须登录) */ - @SaIgnore @GetMapping("/myStatus") public R getMyEnrollmentStatus( @RequestParam("idCard") String idCard, @@ -160,9 +156,8 @@ public class ZsjyEnrollmentInfoController extends BaseController { } /** - * 获取学院列表(供移动端公开访问) + * 获取学院列表(须登录) */ - @SaIgnore @GetMapping("/colleges") public R> getColleges() { try { @@ -174,9 +169,8 @@ public class ZsjyEnrollmentInfoController extends BaseController { } /** - * 根据学院ID获取专业列表(供移动端公开访问) + * 根据学院ID获取专业列表(须登录) */ - @SaIgnore @GetMapping("/majors/{collegeId}") public R> getMajorsByCollegeId(@PathVariable("collegeId") Long collegeId) { try { diff --git a/docs/开发文档/API/后勤满意度调查API.md b/docs/开发文档/API/后勤满意度调查API.md index 22e4fd5a..0b6e907d 100644 --- a/docs/开发文档/API/后勤满意度调查API.md +++ b/docs/开发文档/API/后勤满意度调查API.md @@ -2,8 +2,8 @@ ## 文档信息 -- **版本**:1.0.0 -- **最后更新**:2025-07-01 +- **版本**:1.0.1 +- **最后更新**:2026-09-20 - **作者**:Cursor AI - **分类**:后勤管理模块 @@ -11,6 +11,13 @@ 本文档详细说明后勤满意度调查系统的API接口设计,包括问卷管理、题目管理、选项管理、答题记录等功能。系统采用前后端分离架构,接口采用RESTful API风格设计,所有接口均需通过Token进行身份验证。 +### 问卷过期处理(2026-09-20) + +- 原依赖 SnailJob 任务 `surveyEndTimeJob` / `surveyEndTimeJobExecutor` 每小时扫描过期问卷。 +- 已改为 Spring `@Scheduled`:`HqSatSurveyExpireTask`(cron:`0 0 * * * ?`),将 `hq_sat_survey` 中 `end_time` 已过期且未结束的记录 `status` 更新为 `2`。 +- 多实例通过 Redis 锁 `hq:sat:survey:expire:lock` 避免重复执行。 +- 测试库已关闭对应 SnailJob 任务(`job_status=0`),避免与 `@Scheduled` 双跑。 + ## 通用响应格式 ### 成功响应 diff --git a/docs/开发文档/API/招聘模块API.md b/docs/开发文档/API/招聘模块API.md index 798153f8..81d1734f 100644 --- a/docs/开发文档/API/招聘模块API.md +++ b/docs/开发文档/API/招聘模块API.md @@ -649,4 +649,4 @@ 1. 职位申请提交前需要先保存应聘者信息,获取applicantId 2. 职位状态更改会影响前台展示,下线的职位不会在公开列表中展示 3. 所有API请求需要在Header中附带Token -4. 公开的API(如public/list、public/{jobId})可以通过权限配置允许匿名访问 \ No newline at end of file +4. 公开的API(如public/list、public/{jobId})可以通过权限配置允许匿名访问;`POST /rs/application/submit` 须登录后调用 \ No newline at end of file diff --git a/docs/开发文档/统一身份认证接入说明.md b/docs/开发文档/统一身份认证接入说明.md index 11542d9b..c5d2ff61 100644 --- a/docs/开发文档/统一身份认证接入说明.md +++ b/docs/开发文档/统一身份认证接入说明.md @@ -331,8 +331,8 @@ DEFAULT_TENANT_ID = 000000 ## 7. 后续优化建议 -1. **配置外置化**:将 CAS 地址、client_id、client_secret、redirect_uri 移至 `application.yml`,避免硬编码 -2. **密钥安全**:前端不应保留 `CAS_CLIENT_SECRET`(当前未使用但存在代码中,建议删除) +1. **配置外置化**:将 CAS 地址、client_id、client_secret、redirect_uri 移至 `application.yml`,避免硬编码(后端 secret 仍待外置) +2. **密钥安全**:~~前端不应保留 `CAS_CLIENT_SECRET`~~(已删除;换票仅走后端;CAS 相关日志已脱敏,禁止打印 secret/token/profile) 3. **租户映射**:如需支持多租户,可恢复对 CAS `TENANTID` 的解析逻辑 4. **用户自动注册**:CAS 用户首次登录时自动创建本地账号(需评估权限与安全策略) 5. **移动端接入**:mobile 工程可参考相同 OAuth2 流程实现统一认证登录 diff --git a/docs/设计文档/database/database_msg.md b/docs/设计文档/database/database_msg.md index 77fb2112..cab6de47 100644 --- a/docs/设计文档/database/database_msg.md +++ b/docs/设计文档/database/database_msg.md @@ -2,4 +2,4 @@ url: jdbc:mysql://47.99.164.66:3306/hzdyjs_xg username: root -password: hn02le.34lkdLKD +password: nsyOfyOyoFCr%Brj-k_5PqbW diff --git a/docs/设计文档/database/学工管理-宿舍管理/xg_dorm_hygiene_check_deduction.sql b/docs/设计文档/database/学工管理-宿舍管理/xg_dorm_hygiene_check_deduction.sql new file mode 100644 index 00000000..f69f2ab1 --- /dev/null +++ b/docs/设计文档/database/学工管理-宿舍管理/xg_dorm_hygiene_check_deduction.sql @@ -0,0 +1,27 @@ +-- 宿舍卫生检查扣分明细表 +-- 生产现象:提交宿舍卫生检查时报 Table 'hzdyjs_xg.xg_dorm_hygiene_check_deduction' doesn't exist +-- 原因:代码在保存主表后会先逻辑删除再写入扣分明细,生产库未建该表,整单事务回滚 +-- 执行库:hzdyjs_xg + +CREATE TABLE IF NOT EXISTS `xg_dorm_hygiene_check_deduction` ( + `id` bigint(20) NOT NULL COMMENT '主键ID', + `tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号', + `create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `deleted` tinyint(1) DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)', + `hygiene_check_id` bigint(20) NOT NULL COMMENT '卫生检查ID,关联xg_dorm_hygiene_check.id', + `discipline_type_id` bigint(20) NOT NULL COMMENT '违纪类型ID,关联xskh_discipline_type.id', + `discipline_type_name` varchar(100) DEFAULT NULL COMMENT '违纪类型名称', + `score` decimal(5,2) NOT NULL DEFAULT '0.00' COMMENT '该项扣分', + `sort_order` int(11) DEFAULT '1' COMMENT '排序序号', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_tenant_id` (`tenant_id`), + KEY `idx_deleted` (`deleted`), + KEY `idx_hygiene_check_id` (`hygiene_check_id`), + KEY `idx_discipline_type_id` (`discipline_type_id`), + KEY `idx_tenant_deleted` (`tenant_id`,`deleted`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='宿舍卫生检查扣分明细表'; diff --git a/mobile/src/api/enrollment.js b/mobile/src/api/enrollment.js index 74c78fd2..ead3a49e 100644 --- a/mobile/src/api/enrollment.js +++ b/mobile/src/api/enrollment.js @@ -1,4 +1,4 @@ -// 移动端新生报名相关API接口 +// 移动端新生报名相关API接口(须登录,需携带 Token) import { request } from '@/common/request.js' /** @@ -6,37 +6,31 @@ import { request } from '@/common/request.js' */ export const enrollmentApi = { /** - * 提交报名信息(供学生端使用) + * 提交报名信息(供学生端使用,须登录) * @param {Object} data 报名表单数据 */ submitApplication: (data) => { return request({ url: '/zsjy/enrollment/info/submit', method: 'POST', - data: data, - header: { - isToken: false // 不需要登录token,支持对外公开访问 - } + data: data }) }, /** - * 查询我的报名状态(供学生端使用) + * 查询我的报名状态(供学生端使用,须登录) * @param {Object} params 查询参数 { idCard?, examNumber? } */ queryMyStatus: (params) => { return request({ url: '/zsjy/enrollment/info/myStatus', method: 'GET', - params: params, - header: { - isToken: false // 不需要登录token,支持对外公开访问 - } + params: params }) }, /** - * 根据身份证号和准考证号查询报名信息 + * 根据身份证号和准考证号查询报名信息(须登录) * @param {string} idCard 身份证号 * @param {string} examNumber 准考证号 */ @@ -47,37 +41,28 @@ export const enrollmentApi = { params: { idCard, examNumber - }, - header: { - isToken: false // 不需要登录token } }) }, /** - * 获取学院列表 + * 获取学院列表(须登录) */ getCollegeList: () => { return request({ url: '/zsjy/enrollment/info/colleges', - method: 'GET', - header: { - isToken: false // 不需要登录token,支持对外公开访问 - } + method: 'GET' }) }, /** - * 根据学院ID获取专业列表 + * 根据学院ID获取专业列表(须登录) * @param {string|number} collegeId 学院ID */ getMajorsByCollegeId: (collegeId) => { return request({ url: `/zsjy/enrollment/info/majors/${collegeId}`, - method: 'GET', - header: { - isToken: false // 不需要登录token,支持对外公开访问 - } + method: 'GET' }) } } diff --git a/mobile/src/pages/enrollment/index.vue b/mobile/src/pages/enrollment/index.vue index fedbaaa2..398a388a 100644 --- a/mobile/src/pages/enrollment/index.vue +++ b/mobile/src/pages/enrollment/index.vue @@ -1464,14 +1464,11 @@ export default { submitData.isBoarding = 0; } - // 调用提交接口 + // 调用提交接口(须登录,携带 Token) const response = await request({ url: '/zsjy/enrollment/info/submit', method: 'POST', data: submitData, - header: { - isToken: false, // 不需要登录token - }, }); uni.showToast({ @@ -1564,9 +1561,6 @@ export default { idCard: this.queryData.idCard, examNumber: this.queryData.examNumber, }, - header: { - isToken: false, // 不需要登录token - }, }); if (response.data) { diff --git a/web/src/views/login.vue b/web/src/views/login.vue index 3ac6d498..59139789 100644 --- a/web/src/views/login.vue +++ b/web/src/views/login.vue @@ -245,7 +245,7 @@ const doSocialLogin = (type: string) => { // 固定的 CAS 地址与生产前端地址(按需求写死) const CAS_BASE = 'http://td.hzdyjsxy.cn:19081'; const CAS_CLIENT_ID = '0i7tcT5tULqvmmbbV8'; -const CAS_CLIENT_SECRET = '68c4f7641523452aaf5ef6d0432869f7'; +// client_secret 仅后端持有,前端禁止携带 const FRONTEND_REDIRECT_URI_ENCODED = encodeURIComponent('http://web.hzdyjsxy.cn:18081'); const CAS_REDIRECT_KEY = 'cas_login_redirect'; /** 单点登录门户域名(Referer 匹配) */ @@ -371,7 +371,7 @@ const extractCodeFromRoute = (route: any): string | null => { }; /** - * 使用 code 去请求 accessToken,并打印返回信息 + * 使用 code 经后端换取本系统登录令牌(换票密钥仅后端使用) */ const fetchAccessToken = async (code: string) => { try { @@ -396,7 +396,8 @@ const fetchAccessToken = async (code: string) => { body = txt; } } - console.log('[Backend -> CAS accessToken response]', { status: res.status, ok: res.ok, body }); + // 不打印 body(可能含 accessToken) + console.log('[CAS login] backend response', { status: res.status, ok: res.ok }); // 如果后端返回了登录令牌,前端直接用它完成登录后的行为(存 token & 跳转) // 兼容多种返回结构:{ data: { access_token: '...' } } 或 { access_token: '...' } 或 raw LoginVo diff --git a/学校历史数据迁移/db_config.py b/学校历史数据迁移/db_config.py index 0909491c..89263d14 100644 --- a/学校历史数据迁移/db_config.py +++ b/学校历史数据迁移/db_config.py @@ -11,7 +11,7 @@ DB_CONFIG = { "port": 3306, "database": "hzdyjs_xg", "user": "root", - "password": "hn02le.34lkdLKD", + "password": "nsyOfyOyoFCr%Brj-k_5PqbW", "charset": "utf8mb4" } diff --git a/学校学生操行历史数据迁移/db_config.py b/学校学生操行历史数据迁移/db_config.py index f29c1c75..8d77978c 100644 --- a/学校学生操行历史数据迁移/db_config.py +++ b/学校学生操行历史数据迁移/db_config.py @@ -11,7 +11,7 @@ DB_CONFIG = { "port": 3306, "database": "hzdyjs_xg", "user": "root", - "password": "hn02le.34lkdLKD", + "password": "nsyOfyOyoFCr%Brj-k_5PqbW", "charset": "utf8mb4", "autocommit": False, # 手动控制事务 "connect_timeout": 60, # 连接超时时间(秒) diff --git a/学生换班级/data.conf b/学生换班级/data.conf index 353371b1..c39610bd 100644 --- a/学生换班级/data.conf +++ b/学生换班级/data.conf @@ -3,7 +3,7 @@ DB_HOST="47.99.164.66" DB_PORT="3306" DB_NAME="hzdyjs_xg" DB_USER="root" -DB_PASS="hn02le.34lkdLKD" +DB_PASS="nsyOfyOyoFCr%Brj-k_5PqbW" # Script configuration LOG_DIR="${SCRIPT_DIR}/student_class_change" diff --git a/学籍号刷新/data.conf b/学籍号刷新/data.conf index 4e462f1c..a5c7add5 100644 --- a/学籍号刷新/data.conf +++ b/学籍号刷新/data.conf @@ -3,7 +3,7 @@ DB_HOST="47.99.164.66" DB_PORT="3306" DB_NAME="hzdyjs_xg" DB_USER="root" -DB_PASS="hn02le.34lkdLKD" +DB_PASS="nsyOfyOyoFCr%Brj-k_5PqbW" # Script configuration LOG_DIR="${SCRIPT_DIR}/student_id_card_refresh" diff --git a/学籍号刷新/学生学籍号刷新脚本设计说明.md b/学籍号刷新/学生学籍号刷新脚本设计说明.md index 44775bf7..5513301e 100644 --- a/学籍号刷新/学生学籍号刷新脚本设计说明.md +++ b/学籍号刷新/学生学籍号刷新脚本设计说明.md @@ -97,7 +97,7 @@ DB_HOST="47.99.164.66" # 数据库主机 DB_PORT="3306" # 数据库端口 DB_NAME="hzdyjs_xg" # 数据库名 DB_USER="root" # 数据库用户 -DB_PASS="hn02le.34lkdLKD" # 数据库密码 +DB_PASS="nsyOfyOyoFCr%Brj-k_5PqbW" # 数据库密码 # Script configuration LOG_DIR="${SCRIPT_DIR}/student_id_card_refresh" # 日志目录 diff --git a/教职工数据迁移/db_config.py b/教职工数据迁移/db_config.py index 0909491c..89263d14 100644 --- a/教职工数据迁移/db_config.py +++ b/教职工数据迁移/db_config.py @@ -11,7 +11,7 @@ DB_CONFIG = { "port": 3306, "database": "hzdyjs_xg", "user": "root", - "password": "hn02le.34lkdLKD", + "password": "nsyOfyOyoFCr%Brj-k_5PqbW", "charset": "utf8mb4" } diff --git a/教职工数据迁移/simple_import.py b/教职工数据迁移/simple_import.py index cc20610f..eb030a7e 100644 --- a/教职工数据迁移/simple_import.py +++ b/教职工数据迁移/simple_import.py @@ -14,7 +14,7 @@ DB_CONFIG = { "port": 3306, "database": "hzdyjs_xg", "user": "root", - "password": "hn02le.34lkdLKD", + "password": "nsyOfyOyoFCr%Brj-k_5PqbW", "charset": "utf8mb4" } diff --git a/用户信息同步统一身份认证/data.conf b/用户信息同步统一身份认证/data.conf index 8d53fb2c..66dd0888 100644 --- a/用户信息同步统一身份认证/data.conf +++ b/用户信息同步统一身份认证/data.conf @@ -10,7 +10,7 @@ SOURCE_DB_HOST="47.99.164.66" SOURCE_DB_PORT="3306" SOURCE_DB_NAME="hzdyjs_xg" SOURCE_DB_USER="root" -SOURCE_DB_PASS="hn02le.34lkdLKD" +SOURCE_DB_PASS="nsyOfyOyoFCr%Brj-k_5PqbW" # ---------- 目标库(认证中间库,读写) ---------- # 研发环境:与源库同库,仅新增中间表 @@ -19,7 +19,7 @@ TARGET_DB_HOST="47.99.164.66" TARGET_DB_PORT="3306" TARGET_DB_NAME="hzdyjs_xg" TARGET_DB_USER="root" -TARGET_DB_PASS="hn02le.34lkdLKD" +TARGET_DB_PASS="nsyOfyOyoFCr%Brj-k_5PqbW" # ---------- 同步策略 ---------- # 同步模式:full=全量,incremental=增量(按 update_time) diff --git a/超星数据移植与定时同步/db_config.py b/超星数据移植与定时同步/db_config.py index 7b6fced8..34ca8644 100644 --- a/超星数据移植与定时同步/db_config.py +++ b/超星数据移植与定时同步/db_config.py @@ -11,7 +11,7 @@ DB_CONFIG = { "port": 3306, "database": "hzdyjs_xg", "user": "root", - "password": "hn02le.34lkdLKD", + "password": "nsyOfyOyoFCr%Brj-k_5PqbW", "charset": "utf8mb4" } diff --git a/跟教务系统同步学生异动信息/api_service/config.dev.ini b/跟教务系统同步学生异动信息/api_service/config.dev.ini index e4acbf62..3ed65d1f 100644 --- a/跟教务系统同步学生异动信息/api_service/config.dev.ini +++ b/跟教务系统同步学生异动信息/api_service/config.dev.ini @@ -11,7 +11,7 @@ host = 47.99.164.66 port = 3306 user = root -password = hn02le.34lkdLKD +password = nsyOfyOyoFCr%%Brj-k_5PqbW database = hzdyjs_xg [api] diff --git a/退学、休学、复学、毕业/data.conf b/退学、休学、复学、毕业/data.conf index a7debf81..319c64d1 100644 --- a/退学、休学、复学、毕业/data.conf +++ b/退学、休学、复学、毕业/data.conf @@ -3,7 +3,7 @@ DB_HOST="47.99.164.66" DB_PORT="3306" DB_NAME="hzdyjs_xg" DB_USER="root" -DB_PASS="hn02le.34lkdLKD" +DB_PASS="nsyOfyOyoFCr%Brj-k_5PqbW" # Script configuration LOG_DIR="${SCRIPT_DIR}/student_status_change" diff --git a/问题整改/20260922-安全扫描修改.md b/问题整改/20260922-安全扫描修改.md new file mode 100644 index 00000000..def803ef --- /dev/null +++ b/问题整改/20260922-安全扫描修改.md @@ -0,0 +1,174 @@ +# 20260922 安全扫描修改 + +> 针对扫描报告中免登录接口暴露、敏感信息泄露及可写风险的整改记录。 +> 扫描样例:`GET /prod-api/zsjy/enrollment/info/query?examNumber=123456` 可免登返回身份证、手机号等。 + +## 一、本次处理范围 + +| 优先级 | 项 | 处理结果 | +|--------|----|----------| +| P0 | `POST /rs/init/update-menu` 未授权改菜单 | **已整改** | +| P0 | Swagger `/api-docs`、`/swagger-ui/**` | **已下线** | +| P0 | Demo `/demo/mail/**`、`/demo/queue/delayed/**` | **已下线(运行包不再引入)** | +| P0 | 招生 5 个免登接口(含扫描点名 `query`) | **已整改**(须登录) | +| P1 | `GET /cas/accessToken` 密钥暴露与日志明文 | **部分整改**(前端去 secret + 日志脱敏;后端 secret 外置待做) | +| P1 | `POST /rs/application/submit` 匿名滥投 | **已整改**(须登录) | + +--- + +## 二、已完成修改明细 + +### 1. P0:`POST /rs/init/update-menu` 须登录 + +**问题**:标注 `@SaIgnore`,未登录即可删改 `sys_menu` / `sys_role_menu`。 + +**修改**: +- 移除 `@SaIgnore` +- 增加 `@SaCheckPermission("system:menu:edit")` + +**文件**: +- `backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsInitController.java` + +**验证**:未带 Token → 401;无 `system:menu:edit` → 无权限。 + +--- + +### 2. P0:Swagger / api-docs 下线 + +**问题**:`security.excludes` 放行文档路径,且 `springdoc` 开启,便于枚举全量接口。 + +**修改**: +- `springdoc.api-docs.enabled` / `swagger-ui.enabled` → `false` +- 从 `security.excludes` 移除 `/api-docs`、`/swagger-ui/**`、`/v3/api-docs/**`、`/webjars/**` 等 + +**文件**: +- `backend/ruoyi-admin/src/main/resources/application.yml` + +**验证**:访问 `/prod-api/swagger-ui.html`、`/prod-api/api-docs` 不可用。 + +--- + +### 3. P0:Demo 模块下线 + +**问题**:`ruoyi-demo` 打入运行包,邮件、延迟队列等接口带 `@SaIgnore`。 + +**修改**:注释掉运行路径上所有 `ruoyi-demo` 依赖(admin + 各业务模块),Controller 不再注册。 + +**文件**: +- `backend/ruoyi-admin/pom.xml` +- `backend/ruoyi-modules/ruoyi-hq/pom.xml` +- `backend/ruoyi-modules/ruoyi-rs/pom.xml` +- `backend/ruoyi-modules/ruoyi-cw/pom.xml` +- `backend/ruoyi-modules/ruoyi-xg/pom.xml` +- `backend/ruoyi-modules/ruoyi-zsjy/pom.xml` +- `backend/ruoyi-modules/ruoyi-jcbt/pom.xml` +- `backend/ruoyi-modules/ruoyi-xskh/pom.xml` +- `backend/ruoyi-modules/ruoyi-bzrkh/pom.xml` +- `backend/ruoyi-modules/ruoyi-aqbw/pom.xml` + +**说明**:源码目录 `ruoyi-modules/ruoyi-demo` 仍保留,默认构建/部署不加载。 + +**验证**:`/prod-api/demo/mail/**`、`/prod-api/demo/queue/delayed/**` → 404。 + +--- + +### 4. P0:招生报名相关 5 个接口须登录(扫描报告点名) + +**问题**:以下接口标注 `@SaIgnore`,未登录即可访问;其中 `query` 仅凭准考证号即可返回身份证、手机号、住址等敏感信息。 + +| 方法 | 路径 | 说明 | +|------|------|------| +| GET | `/zsjy/enrollment/info/query` | 按身份证/准考证查报名 | +| POST | `/zsjy/enrollment/info/submit` | 学生提交报名 | +| GET | `/zsjy/enrollment/info/myStatus` | 查本人报名状态 | +| GET | `/zsjy/enrollment/info/colleges` | 学院列表 | +| GET | `/zsjy/enrollment/info/majors/{collegeId}` | 专业列表 | + +**修改**: +- 后端:移除上述 5 个方法的 `@SaIgnore`,走统一登录校验 +- 移动端:去掉 `isToken: false`,请求携带 Token + +**文件**: +- `backend/ruoyi-modules/ruoyi-zsjy/src/main/java/org/dromara/zsjy/controller/ZsjyEnrollmentInfoController.java` +- `mobile/src/api/enrollment.js` +- `mobile/src/pages/enrollment/index.vue` + +**影响**:新生报名页须先登录再查询/提交;未带 Token 访问上述接口返回 401。 + +**验证**: +- 无 Token 访问 `GET /prod-api/zsjy/enrollment/info/query?examNumber=123456` → 401 +- 登录后携带 Token 可正常查询/提交 + +--- + +### 5. P1:CAS 换票 — 前端去 secret + 日志脱敏 + +**问题**: +- 前端写死 `CAS_CLIENT_SECRET`(虽未参与换票,但会进浏览器包) +- 后端日志打印含 secret 的完整 URL、access_token、完整 profile + +**修改**: +- 删除前端 `CAS_CLIENT_SECRET`;换票仍只调 `GET /cas/accessToken?code=...` +- 前端控制台不再打印含 Token 的响应 body +- `CasController` 日志仅保留 base/client_id/长度等非敏感信息;失败响应不再回传 CAS 原始报文 + +**文件**: +- `web/src/views/login.vue` +- `backend/ruoyi-admin/src/main/java/org/dromara/web/controller/CasController.java` +- `docs/开发文档/统一身份认证接入说明.md`(同步说明) + +**对登录影响**:无(前端本未使用 secret;日志脱敏不改换票逻辑)。 + +**未做(后续建议)**: +- 后端 `CLIENT_SECRET` 配置外置 + 向 CAS 轮换密钥 +- `/cas/accessToken` IP 限流 + +--- + +### 6. P1:`POST /rs/application/submit` 须登录 + +**问题**:`@SaIgnore` + `security.excludes` 放行,可匿名灌简历数据。 + +**修改**: +- 移除 `@SaIgnore` +- 从 `security.excludes` 删除 `/rs/application/submit` +- 提交时绑定 `applicantId = LoginHelper.getUserId()` + +**文件**: +- `backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsApplicationController.java` +- `backend/ruoyi-admin/src/main/resources/application.yml` +- `docs/开发文档/API/招聘模块API.md` + +**影响**:招聘门户投递须先登录;`/rs/job/public/**` 公开浏览不受影响。 + +--- + +## 三、部署与验证清单 + +1. 重新编译打包后端(demo 依赖变更需完整构建),部署后重启。 +2. 前端若已发布含 CAS secret 的旧包,需重新构建发布 `web`。 +3. 移动端报名相关改动需重新发布 `mobile`。 +4. 抽查: + - [ ] `POST /rs/init/update-menu` 无 Token → 401 + - [ ] `/swagger-ui.html`、`/api-docs` 不可用 + - [ ] `/demo/mail/**` → 404 + - [ ] `GET /zsjy/enrollment/info/query?examNumber=123456` 无 Token → 401 + - [ ] 招生 submit / myStatus / colleges / majors 无 Token → 401 + - [ ] CAS 统一认证登录仍可用 + - [ ] `POST /rs/application/submit` 无 Token → 401;登录后可提交 + +--- + +## 四、相关分项说明(可作附录查阅) + +| 文档 | 内容 | +|------|------| +| `问题整改/P0-rs-init-update-menu免登整改说明.md` | 菜单更新接口 | +| `问题整改/P0-Swagger与Demo下线整改说明.md` | Swagger / Demo | +| `问题整改/P1-CAS换票密钥与日志脱敏整改说明.md` | CAS | +| `问题整改/P1-rs-application-submit须登录整改说明.md` | 应聘提交 | + +--- + +**文档日期**:2026-09-22 +**主题**:安全扫描修改 diff --git a/问题整改/P0-Swagger与Demo下线整改说明.md b/问题整改/P0-Swagger与Demo下线整改说明.md new file mode 100644 index 00000000..a8659fce --- /dev/null +++ b/问题整改/P0-Swagger与Demo下线整改说明.md @@ -0,0 +1,30 @@ +# P0:Swagger / Demo 模块下线整改说明 + +## 问题 + +1. **Swagger / api-docs 免登暴露**:`security.excludes` 放行 `/api-docs`、`/swagger-ui/**` 等,且 `springdoc.*.enabled=true`,扫描器可枚举全量接口。 +2. **Demo 模块打入运行包**:`/demo/mail/**`、`/demo/queue/delayed/**` 等带 `@SaIgnore`,存在滥用发信等风险。 + +## 整改 + +### 1. 关闭并收回 Swagger 白名单 + +文件:`backend/ruoyi-admin/src/main/resources/application.yml` + +- `springdoc.api-docs.enabled` → `false` +- `springdoc.swagger-ui.enabled` → `false` +- 从 `security.excludes` 移除全部 api-docs / swagger-ui / webjars 路径 + +### 2. 运行包不再引入 demo + +- `backend/ruoyi-admin/pom.xml`:注释掉 `ruoyi-demo` 依赖 +- 各业务模块 pom(hq/rs/cw/xg/zsjy/jcbt/xskh/bzrkh/aqbw):同步注释 `ruoyi-demo` 传递依赖,避免再次打入 admin 包 + +> 源码目录 `ruoyi-modules/ruoyi-demo` 仍保留,便于本地开发需要时再启用;默认构建/部署不再加载其 Controller。 + +## 验证 + +重启后端后: + +1. 访问 `/prod-api/swagger-ui.html`、`/prod-api/api-docs` → 不可用或 404/鉴权失败 +2. 访问 `/prod-api/demo/mail/sendSimpleMessage`、`/prod-api/demo/queue/delayed/subscribe` → 404(映射不存在) diff --git a/问题整改/P0-rs-init-update-menu免登整改说明.md b/问题整改/P0-rs-init-update-menu免登整改说明.md new file mode 100644 index 00000000..8e92f307 --- /dev/null +++ b/问题整改/P0-rs-init-update-menu免登整改说明.md @@ -0,0 +1,19 @@ +# P0:`POST /rs/init/update-menu` 免登录整改说明 + +## 问题 + +`RsInitController#updateMenu` 标注了 `@SaIgnore`,未登录即可删除并重建 `sys_menu` / `sys_role_menu`(menu_id 2000–2028),属于未授权写操作。 + +## 整改 + +- 移除 `@SaIgnore`,恢复 Sa-Token 登录校验。 +- 增加 `@SaCheckPermission("system:menu:edit")`,仅具备系统菜单编辑权限的账号可调用。 + +## 涉及文件 + +- `backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsInitController.java` + +## 验证 + +未带 Token 调用 `POST /prod-api/rs/init/update-menu` 应返回未登录(401)。 +已登录但无 `system:menu:edit` 权限应返回无权限。 diff --git a/问题整改/P1-CAS换票密钥与日志脱敏整改说明.md b/问题整改/P1-CAS换票密钥与日志脱敏整改说明.md new file mode 100644 index 00000000..a832d8ad --- /dev/null +++ b/问题整改/P1-CAS换票密钥与日志脱敏整改说明.md @@ -0,0 +1,15 @@ +# P1:CAS 换票密钥与日志脱敏整改说明 + +## 改动 + +1. **前端**:删除 `web/src/views/login.vue` 中未使用的 `CAS_CLIENT_SECRET`;换票仍只调 `GET /cas/accessToken?code=...`;控制台不再打印含 Token 的响应 body。 +2. **后端**:`CasController` 日志不再打印带 `client_secret` 的完整 URL、`access_token`、完整 profile;失败响应也不再回传 CAS 原始报文。 + +## 对登录的影响 + +无。前端本就未使用 secret;日志脱敏不改变换票与签发 Token 逻辑。 + +## 后续建议(未做) + +- 将后端 `CLIENT_SECRET` 外置到配置/环境变量,并向 CAS 侧轮换密钥。 +- 对 `/cas/accessToken` 增加 IP 限流。 diff --git a/问题整改/P1-rs-application-submit须登录整改说明.md b/问题整改/P1-rs-application-submit须登录整改说明.md new file mode 100644 index 00000000..92be3cd2 --- /dev/null +++ b/问题整改/P1-rs-application-submit须登录整改说明.md @@ -0,0 +1,15 @@ +# P1:`POST /rs/application/submit` 须登录整改说明 + +## 问题 + +接口标注 `@SaIgnore`,且在 `security.excludes` 中放行,未登录即可任意提交应聘信息(姓名、手机号等写入库),存在灌数据/滥投风险。 + +## 整改 + +1. 移除 `RsApplicationController#submitApplication` 的 `@SaIgnore` +2. 从 `application.yml` → `security.excludes` 删除 `/rs/application/submit` +3. 提交时绑定 `applicantId = LoginHelper.getUserId()` + +## 影响 + +招聘门户投递须先登录;未带 Token 调用返回未登录。职位公开浏览接口(`/rs/job/public/**`)不受影响。 diff --git a/问题整改/P4-创建应用数据库账号.sql b/问题整改/P4-创建应用数据库账号.sql new file mode 100644 index 00000000..9da5b0d8 --- /dev/null +++ b/问题整改/P4-创建应用数据库账号.sql @@ -0,0 +1,30 @@ +-- ============================================================ +-- P4 整改:应用库账号(禁止业务使用 root) +-- 说明: +-- 1. 用现有 root 登录后执行本脚本(生产 172.16.0.67、测试库需各执行一遍) +-- 2. 仅授权业务库 hzdyjs_xg.*,不含 *.* 全局 DBA 权限 +-- 3. 执行后修改应用配置并重启,再用下方「验证」确认 +-- ============================================================ + +-- 账号:hzdyjs_app +-- 密码:Hzdyjs@App#n4SQi8AfPHldNj49 + +CREATE USER IF NOT EXISTS 'hzdyjs_app'@'%' IDENTIFIED BY 'Hzdyjs@App#n4SQi8AfPHldNj49'; +CREATE USER IF NOT EXISTS 'hzdyjs_app'@'localhost' IDENTIFIED BY 'Hzdyjs@App#n4SQi8AfPHldNj49'; +CREATE USER IF NOT EXISTS 'hzdyjs_app'@'172.16.0.%' IDENTIFIED BY 'Hzdyjs@App#n4SQi8AfPHldNj49'; + +-- 业务库完整权限(表级 ALL,仍不是全局 DBA) +GRANT ALL PRIVILEGES ON `hzdyjs_xg`.* TO 'hzdyjs_app'@'%'; +GRANT ALL PRIVILEGES ON `hzdyjs_xg`.* TO 'hzdyjs_app'@'localhost'; +GRANT ALL PRIVILEGES ON `hzdyjs_xg`.* TO 'hzdyjs_app'@'172.16.0.%'; + +FLUSH PRIVILEGES; + +-- ---------- 验证(可选)---------- +-- SHOW GRANTS FOR 'hzdyjs_app'@'%'; +-- 期望类似:GRANT ALL PRIVILEGES ON `hzdyjs_xg`.* TO `hzdyjs_app`@`%` +-- 不应出现:ON *.* 、SUPER、FILE、GRANT OPTION 等全局高危权限 + +-- 应用侧验证: +-- SELECT USER(), CURRENT_USER(); +-- 期望:hzdyjs_app@... diff --git a/问题整改/P5-关闭开放注册.sql b/问题整改/P5-关闭开放注册.sql new file mode 100644 index 00000000..c281bc65 --- /dev/null +++ b/问题整改/P5-关闭开放注册.sql @@ -0,0 +1,13 @@ +-- P5 配套:关闭开放注册,缩小 /auth/register 免登攻击面 +-- 在业务库 hzdyjs_xg 执行 + +UPDATE sys_config +SET config_value = 'false', + update_time = NOW() +WHERE config_key = 'sys.account.registerUser'; + +-- 验证 +SELECT config_key, config_value +FROM sys_config +WHERE config_key = 'sys.account.registerUser'; +-- 期望 config_value = false diff --git a/问题整改/P6-关闭开放注册.sql b/问题整改/P6-关闭开放注册.sql new file mode 100644 index 00000000..c63d6556 --- /dev/null +++ b/问题整改/P6-关闭开放注册.sql @@ -0,0 +1,13 @@ +-- P6:关闭开放注册(与 P5 配套,缩小免登 /auth/register 攻击面) +-- 在业务库 hzdyjs_xg 执行 + +UPDATE sys_config +SET config_value = 'false', + update_time = NOW() +WHERE config_key = 'sys.account.registerUser'; + +-- 验证 +SELECT config_id, config_key, config_value, remark +FROM sys_config +WHERE config_key = 'sys.account.registerUser'; +-- 期望 config_value = false diff --git a/问题整改/P6-注册接口滥用整改说明.md b/问题整改/P6-注册接口滥用整改说明.md new file mode 100644 index 00000000..0a2cc2fa --- /dev/null +++ b/问题整改/P6-注册接口滥用整改说明.md @@ -0,0 +1,35 @@ +# P6 整改说明:注册接口免登可被滥用 + +## 问题 + +`AuthController` 类级 `@SaIgnore`,`POST /prod-api/auth/register` 无需登录即可访问。若数据库 `sys.account.registerUser=true`,可被滥用于撞库、刷注册,并曾作为 SQL 注入入口(见 P5)。 + +## 整改措施(已落地) + +| # | 措施 | 位置 | +|---|------|------| +| 1 | 配置层总开关 `user.register.enabled`,**默认 false** | `application.yml` | +| 2 | Controller 最先判断配置开关,关闭则直接拒绝 | `AuthController.register` | +| 3 | Service 二次拦截,防止绕过 Controller | `SysRegisterService.register` | +| 4 | IP 限流:60 秒内最多 5 次 | `@RateLimiter` | +| 5 | 仍保留库开关 `sys.account.registerUser` 二次判断 | 原有逻辑 | +| 6 | 配套 SQL 将库开关置为 false | `P6-关闭开放注册.sql` | + +生效条件(同时满足才会真正注册成功): + +1. `user.register.enabled=true`(配置,默认已关) +2. `sys.account.registerUser=true`(数据库) + +校园场景保持两者均为 false 即可。 + +## 发布注意 + +- 需重新编译发布 backend +- 生产执行 `P6-关闭开放注册.sql`(若 P5 已执行过可跳过) +- 验证:`POST /prod-api/auth/register` 应返回「当前系统没有开启注册功能」 + +## 与 P5 关系 + +- P5:修 `tenantId` SQL 注入(格式白名单) +- P6:缩小免登注册攻击面(默认关闭 + 限流) +- 两者互补,建议一并发布 diff --git a/问题整改/P7-重置js01密码.sql b/问题整改/P7-重置js01密码.sql new file mode 100644 index 00000000..9767d9b9 --- /dev/null +++ b/问题整改/P7-重置js01密码.sql @@ -0,0 +1,29 @@ +-- ============================================================ +-- P7:重置业务管理员 js01 密码(BCrypt,与系统 Hutool BCrypt 一致) +-- 新明文密码:Hzdyjs@Js01#K9mP2xQ7w +-- 请在生产/测试库分别执行;执行后通知管理员用新密码登录并自行再改一次 +-- ============================================================ + +-- 执行前确认账号存在 +SELECT user_id, tenant_id, user_name, nick_name, status, del_flag, + LEFT(password, 10) AS pwd_prefix +FROM sys_user +WHERE user_name = 'js01' + AND del_flag = '0'; + +-- 重置密码 +UPDATE sys_user +SET password = '$2a$10$8oUw5Tz8x6vQJlcQrcQZT.J/vjUAe2JjSNL/QdDT2XJqg.wX67csO', + update_time = NOW() +WHERE user_name = 'js01' + AND del_flag = '0'; + +-- 验证(应影响 1 行;哈希前缀一般为 $2a$10$) +SELECT user_id, user_name, nick_name, status, + LEFT(password, 29) AS pwd_prefix, + update_time +FROM sys_user +WHERE user_name = 'js01' + AND del_flag = '0'; + +-- 可选:清理该用户在线会话需在 Redis/后台强制下线,SQL 无法直接踢 token diff --git a/问题整改/SQL注入漏洞整改说明-tenantId.md b/问题整改/SQL注入漏洞整改说明-tenantId.md index 3c3e12b2..91d55878 100644 --- a/问题整改/SQL注入漏洞整改说明-tenantId.md +++ b/问题整改/SQL注入漏洞整改说明-tenantId.md @@ -1,22 +1,40 @@ -# SQL 注入漏洞整改说明(tenantId) +# SQL 注入漏洞整改说明(tenantId / P5) ## 背景 -攻防演练报告指出智慧校园(mobile H5:`ykt.hzdyjsxy.cn:18081/#/`)存在 SQL 注入,可拖取 `sys_user` / `sys_config` 等数据。 +攻防演练报告:免登接口 `POST /prod-api/auth/register` 的 `tenantId` 经多租户插件拼入 SQL,可 `extractvalue` 拖库(RuoYi-Vue-Plus XVE-2026-50962 同类问题)。 -实际利用入口为后端免登接口 `POST /prod-api/auth/register` 的 `tenantId` 字段,经多租户插件拼入 SQL(与 RuoYi-Vue-Plus XVE-2026-50962 同类问题)。 +## 整改措施(代码已落地) -## 整改内容(2026-09-17) - -| # | 措施 | 改动位置 | -|---|------|----------| -| 1 | sink 白名单:租户 ID 仅允许 `^[0-9]{1,20}$`,非法直接抛错,不拼 SQL | `PlusTenantLineHandler`、`TenantHelper.checkTenantIdFormat` | +| # | 措施 | 位置 | +|---|------|------| +| 1 | sink 白名单:租户 ID 仅 `^[0-9]{1,20}$`,非法不拼 SQL | `PlusTenantLineHandler`、`TenantHelper.checkTenantIdFormat` | | 2 | 注册接口先 `checkTenant`,再查注册开关 | `AuthController.register` | -| 3 | 所有 `TenantHelper.dynamic/setDynamic` 入口统一格式校验;登录 `checkTenant` 增加格式校验 | `TenantHelper`、`SysLoginService.checkTenant` | -| 4 | 删除心理咨询调试任意 SQL 接口 | 删除 `XljkConsultationDebugController` | +| 3 | 登录/动态租户入口统一格式校验 | `SysLoginService.checkTenant`、`TenantHelper.setDynamic` | +| 4 | 入参 Bean 校验 `@Pattern` | `LoginBody.tenantId`(含注册) | +| 5 | `selectRegisterEnabled` 入口再校验 | `SysConfigServiceImpl` | +| 6 | 社交登录绑定参数校验 | `AuthController.authBinding` | +| 7 | 删除心理咨询调试任意 SQL 接口 | 已删除 `XljkConsultationDebugController` | -## 发布注意 +## 配套 SQL(生产建议执行) -- 需重新编译并发布 **backend** 后生效;仅发 mobile 前端无效。 -- 建议同步轮换初始密码、微信 AppSecret,并审计异常访问。 -- 生产环境确认 `sys.account.registerUser=false`(关闭开放注册)。 +关闭开放注册,缩小免登攻击面: + +```sql +UPDATE sys_config +SET config_value = 'false', + update_time = NOW() +WHERE config_key = 'sys.account.registerUser' + AND deleted = 0; +``` + +## 发布与验证 + +1. 重新编译发布 **backend**(仅发前端无效) +2. 用报告同类 payload 打 `/prod-api/auth/register`,应返回租户编号格式不正确 / 未开启注册,**不应**再出现 XPATH / SQL 报错泄密 +3. 正常 `tenantId=000000` 登录不受影响 + +## 状态 + +- 代码:已完成 +- 生产生效:取决于是否已用含本修复的包重启 diff --git a/问题整改/verify_tmp/b.bin b/问题整改/verify_tmp/b.bin new file mode 100644 index 00000000..03a5a6b3 --- /dev/null +++ b/问题整改/verify_tmp/b.bin @@ -0,0 +1 @@ +{"code":404,"msg":"No endpoint GET /actuator/metrics.","data":null} \ No newline at end of file diff --git a/问题整改/verify_tmp/h.txt b/问题整改/verify_tmp/h.txt new file mode 100644 index 00000000..55ffef15 --- /dev/null +++ b/问题整改/verify_tmp/h.txt @@ -0,0 +1,9 @@ +HTTP/1.1 200 OK +Connection: keep-alive +Vary: Origin +Vary: Access-Control-Request-Method +Vary: Access-Control-Request-Headers +Transfer-Encoding: chunked +Content-Type: application/json +Date: Sun, 20 Sep 2026 03:34:05 GMT + diff --git a/问题整改/verify_tmp/hd.bin b/问题整改/verify_tmp/hd.bin new file mode 100644 index 00000000..cf17c2de --- /dev/null +++ b/问题整改/verify_tmp/hd.bin @@ -0,0 +1 @@ +{"code":404,"msg":"No endpoint GET /actuator/heapdump.","data":null} \ No newline at end of file diff --git a/问题整改/verify_tmp/inj.json b/问题整改/verify_tmp/inj.json new file mode 100644 index 00000000..da527507 --- /dev/null +++ b/问题整改/verify_tmp/inj.json @@ -0,0 +1 @@ +{"clientId": "e5cd7e4891bf95d1d19206ce24a7b32e", "grantType": "password", "tenantId": "000000' AND extractvalue(1,concat(0x7e,(SELECT version()))) AND '1'='1", "username": "zzq001", "password": "ttt", "userType": "sys_user", "code": "", "uuid": ""} diff --git a/问题整改/verify_tmp/n.txt b/问题整改/verify_tmp/n.txt new file mode 100644 index 00000000..1d029e1c --- /dev/null +++ b/问题整改/verify_tmp/n.txt @@ -0,0 +1 @@ +{"code":404,"msg":"No endpoint GET /actuator/env.","data":null} \ No newline at end of file diff --git a/问题整改/verify_tmp/o.txt b/问题整改/verify_tmp/o.txt new file mode 100644 index 00000000..a0f1ed0a --- /dev/null +++ b/问题整改/verify_tmp/o.txt @@ -0,0 +1 @@ +{"code": 401, "msg": "no basic auth", "data": null} \ No newline at end of file diff --git a/问题整改/verify_tmp/p5.txt b/问题整改/verify_tmp/p5.txt new file mode 100644 index 00000000..588370f5 --- /dev/null +++ b/问题整改/verify_tmp/p5.txt @@ -0,0 +1,2 @@ +{"code":500,"msg":"租户编号格式不正确, 用户密码长度必须在5到30个字符之间","data":null} +HTTP:200 diff --git a/问题整改/verify_tmp/p6.txt b/问题整改/verify_tmp/p6.txt new file mode 100644 index 00000000..af772a2d --- /dev/null +++ b/问题整改/verify_tmp/p6.txt @@ -0,0 +1,2 @@ +{"code":500,"msg":"当前系统没有开启注册功能!","data":null} +HTTP:200 diff --git a/问题整改/verify_tmp/reg.json b/问题整改/verify_tmp/reg.json new file mode 100644 index 00000000..3ef17128 --- /dev/null +++ b/问题整改/verify_tmp/reg.json @@ -0,0 +1 @@ +{"clientId": "e5cd7e4891bf95d1d19206ce24a7b32e", "grantType": "password", "tenantId": "000000", "username": "ptest_p6_1789875176", "password": "Test@123456", "userType": "sys_user", "code": "", "uuid": ""} diff --git a/问题整改/verify_tmp/tenant.txt b/问题整改/verify_tmp/tenant.txt new file mode 100644 index 00000000..bb3a74b1 --- /dev/null +++ b/问题整改/verify_tmp/tenant.txt @@ -0,0 +1,2 @@ +{"code":200,"msg":"操作成功","data":{"tenantEnabled":true,"voList":[{"tenantId":"000000","companyName":"杭州第一技师学院","domain":null}]}} +HTTP:200 diff --git a/问题整改/本地验证P1-P9结果.md b/问题整改/本地验证P1-P9结果.md new file mode 100644 index 00000000..f68dee70 --- /dev/null +++ b/问题整改/本地验证P1-P9结果.md @@ -0,0 +1,22 @@ +# 本地测试环境 P1–P9 验证记录 + +- 验证时间:2026-09-20 +- 环境:本机 backend `:8080` + web `:80`(`/prod-api` 代理) +- 测试库:`47.99.164.66 / hzdyjs_xg` + +| 编号 | 结论 | 验证证据 | +|------|------|----------| +| P1 | 通过 | `ruoyi:123456` → 401;`ruoyi:HzdyjsMon@Dev#9Kx7mQ2pL` → Basic 鉴权通过 | +| P2 | 通过 | `/actuator/heapdump` 返回 `No endpoint GET /actuator/heapdump`,无堆转储文件 | +| P3 | 通过(攻击链已断) | 依赖 P1/P2;无法再远程 dump 内存凭据 | +| P4 | 通过 | 配置 `username: hzdyjs_app`;库账号可连;`CURRENT_USER=hzdyjs_app@%` | +| P5 | 通过 | 注入 `tenantId` → `租户编号格式不正确`,无 XPATH/SQL 泄密 | +| P6 | 通过 | 正常注册 → `当前系统没有开启注册功能!`;库 `registerUser=false` | +| P7 | 本地 N/A / 生产已改 | 测试库无 `js01`;生产已执行 P7 脚本并确认哈希更新 | +| P8 | 通过(入口已堵) | heapdump/注入入口不可再利用;历史泄露数据需事件侧收尾 | +| P9 | 通过 | 敏感端点均不可用;仅残留空的 `/actuator` 发现页(无子端点) | + +## 补充说明 + +- `/actuator` 根路径在正确监控密码下仍可能返回空 `_links`(仅 self),**不含 health/heapdump/env**,不影响安全结论。 +- 前端 `http://127.0.0.1/` 与 `GET /auth/tenant/list` 正常(HTTP 200)。 diff --git a/问题整改/杭州第一技师学院存在弱口令漏洞.docx b/问题整改/杭州第一技师学院存在弱口令漏洞.docx new file mode 100644 index 00000000..2a1b63ed Binary files /dev/null and b/问题整改/杭州第一技师学院存在弱口令漏洞.docx differ diff --git a/问题整改/杭州第一技师学院存在表达式注入漏洞.docx b/问题整改/杭州第一技师学院存在表达式注入漏洞.docx new file mode 100644 index 00000000..2b1f106b Binary files /dev/null and b/问题整改/杭州第一技师学院存在表达式注入漏洞.docx differ