diff --git a/doc/部署说明/部署过程描述.md b/doc/部署说明/部署过程描述.md index c3c82822..0ab44f0d 100644 --- a/doc/部署说明/部署过程描述.md +++ b/doc/部署说明/部署过程描述.md @@ -113,7 +113,8 @@ firewall-cmd --add-port={12001,12002,12003,12004}/tcp --permanent firewall-cmd --reload firewall-cmd --list-all - +新版(1.26.0) /usr/local/nginx_new/conf/nginx.conf /usr/local/nginx_new/sbin/nginx +/usr/local/nginx_new/sbin/nginx -t && /usr/local/nginx_new/sbin/nginx -s reload --- ## 10.76.108.4 diff --git a/ng/3/nginx.conf b/ng/3/nginx.conf index d0000065..65238168 100644 --- a/ng/3/nginx.conf +++ b/ng/3/nginx.conf @@ -107,12 +107,12 @@ http { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } - location /efcode20-sup-web/ { - proxy_pass http://10.76.108.15:12004/; - proxy_set_header Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } +# location /efcode20-sup-web/ { +# proxy_pass http://10.76.108.15:12004/; +# proxy_set_header Host $http_host; +# proxy_set_header X-Real-IP $remote_addr; +# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +# } #location ~* /(uploads|images)/.*\.(php|php2|php3|php4|php5|phpm|phpml|phtml|phtm|phps|pht|asp|aspx|asa|cer|cdx|ashx|exe|sh|bash|jsp|jspx|jspa|html|web.config|cfm|cgi|war|ashx|htaccess|py|pl)$ { #deny all; # 拦截.html和.htm文件,并返回403禁止访问 #return 403; @@ -264,15 +264,47 @@ http { proxy_max_temp_file_size 128m; } } +# server { +# listen 85; +# server_name localhost; +# proxy_set_header Host $host; +# proxy_set_header X-real-ip $remote_addr; +# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +# client_max_body_size 100M; +# location / { +# # proxy_pass http://10.76.108.1:85; +# proxy_pass http://java_cluster/; +# proxy_set_header Host $host:$server_port; +# proxy_set_header REMOTE-HOST $remote_addr; +# proxy_set_header X-Real-IP $remote_addr; +# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +# proxy_redirect default; +# proxy_connect_timeout 600s; +# proxy_send_timeout 600s; +# proxy_read_timeout 600s; +# } +# +# location /efcode20-sup-web/ { +# proxy_pass http://10.76.108.15:12004/; +# proxy_set_header Host $http_host; +# proxy_set_header X-Real-IP $remote_addr; +# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; +# } +# } server { - listen 85; + listen 85 ssl; server_name localhost; + + ssl_certificate /efcode20/ssl/selfsigned.crt; + ssl_certificate_key /efcode20/ssl/selfsigned.key; + ssl_protocols TLSv1.2 TLSv1.3; + proxy_set_header Host $host; proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 100M; + location / { - # proxy_pass http://10.76.108.1:85; proxy_pass http://java_cluster/; proxy_set_header Host $host:$server_port; proxy_set_header REMOTE-HOST $remote_addr; diff --git a/zdxt-common/zdxt-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java b/zdxt-common/zdxt-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java index ceb83704..deea5429 100644 --- a/zdxt-common/zdxt-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java +++ b/zdxt-common/zdxt-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java @@ -27,4 +27,11 @@ public interface CacheConstants { */ String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; + /** + * 已注销Token黑名单 redis key 前缀 + * 用于解决 JWT 注销后仍可使用的问题:用户登出时将 token 写入此 key, + * 拦截器在校验登录时会检查命中黑名单的 token 直接拒绝。 + */ + String TOKEN_BLACKLIST_KEY = "token_blacklist:"; + } diff --git a/zdxt-common/zdxt-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java b/zdxt-common/zdxt-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java index 79d58daf..9d788de8 100644 --- a/zdxt-common/zdxt-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java +++ b/zdxt-common/zdxt-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java @@ -37,7 +37,13 @@ public class CryptoFilter implements Filter { HttpServletResponse servletResponse = (HttpServletResponse) response; // 获取加密注解 ApiEncrypt apiEncrypt = this.getApiEncryptAnnotation(servletRequest); + + //不加密 boolean responseFlag = apiEncrypt != null && apiEncrypt.response(); + //加密 + //boolean responseFlag = apiEncrypt == null || apiEncrypt.response(); + + ServletRequest requestWrapper = null; ServletResponse responseWrapper = null; EncryptResponseBodyWrapper responseBodyWrapper = null; diff --git a/zdxt-common/zdxt-common-satoken/src/main/resources/common-satoken.yml b/zdxt-common/zdxt-common-satoken/src/main/resources/common-satoken.yml index 70a327a5..285e7846 100644 --- a/zdxt-common/zdxt-common-satoken/src/main/resources/common-satoken.yml +++ b/zdxt-common/zdxt-common-satoken/src/main/resources/common-satoken.yml @@ -16,4 +16,4 @@ sa-token: # token前缀 token-prefix: "Bearer" # jwt签名密钥(Mixin模式必须配置) - jwt-secret-key: "zdxt-efcode-jwt-secret-key-2026@Secure!" + jwt-secret-key: "xK9jL2mP3qR4sT5uV6wX7yZ8aB1cD2eF4gH4iJ5kL6mN7oP8qR9sT0uV1wX2yZ3aB4cD5eF6gH==" diff --git a/zdxt-common/zdxt-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java b/zdxt-common/zdxt-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java index df53537d..8bdaa6f3 100644 --- a/zdxt-common/zdxt-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java +++ b/zdxt-common/zdxt-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java @@ -12,10 +12,12 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheConstants; import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.utils.ServletUtils; import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.common.security.config.properties.SecurityProperties; import org.dromara.common.security.handler.AllUrlHandler; @@ -62,6 +64,17 @@ public class SecurityConfig implements WebMvcConfigurer { // 检查是否登录 是否有token StpUtil.checkLogin(); + // 检查当前 token 是否在黑名单(已注销) + // JWT Mixin 模式下 token 本身是独立有效的, + // 需要通过黑名单才能让登出后的 token 真正失效 + String tokenValue = StpUtil.getTokenValue(); + if (StringUtils.isNotBlank(tokenValue) + && Boolean.TRUE.equals(RedisUtils.hasKey(CacheConstants.TOKEN_BLACKLIST_KEY + tokenValue))) { + throw NotLoginException.newInstance(StpUtil.getLoginType(), + "-101", "Token 已注销,请重新登录", + tokenValue); + } + // 检查 header 与 param 里的 clientid 与 token 里的是否一致 String headerCid = request.getHeader(LoginHelper.CLIENT_KEY); String paramCid = ServletUtils.getParameter(LoginHelper.CLIENT_KEY); diff --git a/zdxt-web-client/zdxt-admin-plus-ui/src/utils/request.ts b/zdxt-web-client/zdxt-admin-plus-ui/src/utils/request.ts index 8dcd2c74..751c5468 100644 --- a/zdxt-web-client/zdxt-admin-plus-ui/src/utils/request.ts +++ b/zdxt-web-client/zdxt-admin-plus-ui/src/utils/request.ts @@ -45,7 +45,10 @@ service.interceptors.request.use( // 是否需要防止数据重复提交 const isRepeatSubmit = config.headers?.repeatSubmit === false; // 是否需要加密 + // 默认不加密 const isEncrypt = config.headers?.isEncrypt === 'true'; + // 默认加密 + //const isEncrypt = config.headers?.isEncrypt !== false && config.headers?.isEncrypt !== 'false'; if (getToken() && !isToken) { config.headers['Authorization'] = 'Bearer ' + getToken(); // 让每个请求携带自定义token 请根据实际情况自行修改 diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/SysLoginService.java b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/SysLoginService.java index bf1870f4..645079f5 100644 --- a/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/SysLoginService.java +++ b/zdxt-web-server/zdxt-admin-web-server/src/main/java/org/dromara/web/service/SysLoginService.java @@ -106,6 +106,11 @@ public class SysLoginService { /** * 退出登录 + *
+ * Sa-Token JWT Mixin 模式下,StpUtil.logout() 只会清除服务端 session, + * 但已签发的 JWT 本身在原有有效期内仍可被使用。 + * 这里将当前 token 写入 Redis 黑名单(TTL = token 剩余有效期), + * 拦截器会拒绝命中黑名单的 token,从而真正使 JWT 注销生效。 */ public void logout() { try { @@ -121,12 +126,38 @@ public class SysLoginService { } catch (NotLoginException ignored) { } finally { try { + // 将当前 token 加入黑名单,让 JWT 立即失效 + blacklistCurrentToken(); StpUtil.logout(); } catch (NotLoginException ignored) { } } } + /** + * 将当前请求携带的 token 写入 Redis 黑名单,TTL 与 token 剩余有效期对齐。 + */ + private void blacklistCurrentToken() { + try { + String tokenValue = StpUtil.getTokenValue(); + if (StringUtils.isBlank(tokenValue)) { + return; + } + // token 剩余有效期(秒):-1 永久,-2 不存在/已过期 + long timeout = StpUtil.getTokenTimeout(); + String key = CacheConstants.TOKEN_BLACKLIST_KEY + tokenValue; + if (timeout > 0) { + RedisUtils.setCacheObject(key, "1", Duration.ofSeconds(timeout)); + } else if (timeout == -1) { + // 永久 token,黑名单给个较大的默认过期时间(与 sa-token timeout 默认1天一致) + RedisUtils.setCacheObject(key, "1", Duration.ofDays(1)); + } + // timeout == -2 表示 token 已过期,无需加入黑名单 + } catch (Exception e) { + log.warn("将注销 token 加入黑名单失败: {}", e.getMessage()); + } + } + /** * 记录登录信息 * diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application-dev-cust-zrb.yml b/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application-dev-cust-zrb.yml index 2e49a737..a055d637 100644 --- a/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application-dev-cust-zrb.yml +++ b/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application-dev-cust-zrb.yml @@ -21,7 +21,7 @@ spring: driverClassName: com.mysql.cj.jdbc.Driver # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) - url: jdbc:mysql://127.0.0.1:3309/efcode-v2-2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + url: jdbc:mysql://127.0.0.1:3309/efcode-v2-3?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: root diff --git a/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application.yml b/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application.yml index eee4aaa9..ff88638e 100644 --- a/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application.yml +++ b/zdxt-web-server/zdxt-admin-web-server/src/main/resources/application.yml @@ -104,7 +104,7 @@ sa-token: # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) is-share: false # jwt秘钥 - jwt-secret-key: abcdefghijklmnopqrstuvwxyz + jwt-secret-key: "xK9jL2mP3qR4sT5uV6wX7yZ8aB1cD2eF4gH4iJ5kL6mN7oP8qR9sT0uV1wX2yZ3aB4cD5eF6gH==" # security配置 security: