diff --git a/.gitignore b/.gitignore index c2bdfad1c..77eb2ba36 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,8 @@ target/ *.iml *.ipr +### JRebel ### +rebel.xml ### NetBeans ### nbproject/private/ build/* @@ -36,6 +38,7 @@ nbdist/ # Others *.log *.xml.versionsBackup +*.swp !*/build/*.java !*/build/*.html diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GenConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GenConstants.java index 6b7d1497c..684f3cc10 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GenConstants.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GenConstants.java @@ -1,181 +1,186 @@ -package com.ruoyi.common.core.constant; - -/** - * 代码生成通用常量 - * - * @author Lion Li - */ -public interface GenConstants { - /** - * 单表(增删改查) - */ - String TPL_CRUD = "crud"; - - /** - * 树表(增删改查) - */ - String TPL_TREE = "tree"; - - /** - * 主子表(增删改查) - */ - String TPL_SUB = "sub"; - - /** - * 树编码字段 - */ - String TREE_CODE = "treeCode"; - - /** - * 树父编码字段 - */ - String TREE_PARENT_CODE = "treeParentCode"; - - /** - * 树名称字段 - */ - String TREE_NAME = "treeName"; - - /** - * 上级菜单ID字段 - */ - String PARENT_MENU_ID = "parentMenuId"; - - /** - * 上级菜单名称字段 - */ - String PARENT_MENU_NAME = "parentMenuName"; - - /** - * 数据库字符串类型 - */ - String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"}; - - /** - * 数据库文本类型 - */ - String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"}; - - /** - * 数据库时间类型 - */ - String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"}; - - /** - * 数据库数字类型 - */ - String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer", - "bigint", "float", "double", "decimal"}; - - /** - * 页面不需要编辑字段 - */ - String[] COLUMNNAME_NOT_EDIT = {"id", "create_by", "create_time", "del_flag"}; - - /** - * 页面不需要显示的列表字段 - */ - String[] COLUMNNAME_NOT_LIST = {"id", "create_by", "create_time", "del_flag", "update_by", - "update_time"}; - - /** - * 页面不需要查询字段 - */ - String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by", - "update_time", "remark"}; - - /** - * Entity基类字段 - */ - String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime", "remark"}; - - /** - * Tree基类字段 - */ - String[] TREE_ENTITY = {"parentName", "parentId", "orderNum", "ancestors"}; - - /** - * 文本框 - */ - String HTML_INPUT = "input"; - - /** - * 文本域 - */ - String HTML_TEXTAREA = "textarea"; - - /** - * 下拉框 - */ - String HTML_SELECT = "select"; - - /** - * 单选框 - */ - String HTML_RADIO = "radio"; - - /** - * 复选框 - */ - String HTML_CHECKBOX = "checkbox"; - - /** - * 日期控件 - */ - String HTML_DATETIME = "datetime"; - - /** - * 图片上传控件 - */ - String HTML_IMAGE_UPLOAD = "imageUpload"; - - /** - * 文件上传控件 - */ - String HTML_FILE_UPLOAD = "fileUpload"; - - /** - * 富文本控件 - */ - String HTML_EDITOR = "editor"; - - /** - * 字符串类型 - */ - String TYPE_STRING = "String"; - - /** - * 整型 - */ - String TYPE_INTEGER = "Integer"; - - /** - * 长整型 - */ - String TYPE_LONG = "Long"; - - /** - * 浮点型 - */ - String TYPE_DOUBLE = "Double"; - - /** - * 高精度计算类型 - */ - String TYPE_BIGDECIMAL = "BigDecimal"; - - /** - * 时间类型 - */ - String TYPE_DATE = "Date"; - - /** - * 模糊查询 - */ - String QUERY_LIKE = "LIKE"; - - /** - * 需要 - */ - String REQUIRE = "1"; -} +package com.ruoyi.common.core.constant; + +/** + * 代码生成通用常量 + * + * @author Lion Li + */ +public interface GenConstants { + /** + * 单表(增删改查) + */ + String TPL_CRUD = "crud"; + + /** + * 树表(增删改查) + */ + String TPL_TREE = "tree"; + + /** + * 主子表(增删改查) + */ + String TPL_SUB = "sub"; + + /** + * 树编码字段 + */ + String TREE_CODE = "treeCode"; + + /** + * 树父编码字段 + */ + String TREE_PARENT_CODE = "treeParentCode"; + + /** + * 树名称字段 + */ + String TREE_NAME = "treeName"; + + /** + * 上级菜单ID字段 + */ + String PARENT_MENU_ID = "parentMenuId"; + + /** + * 上级菜单名称字段 + */ + String PARENT_MENU_NAME = "parentMenuName"; + + /** + * 数据库字符串类型 + */ + String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"}; + + /** + * 数据库文本类型 + */ + String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"}; + + /** + * 数据库时间类型 + */ + String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"}; + + /** + * 数据库数字类型 + */ + String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer", + "bigint", "float", "double", "decimal"}; + + /** + * 页面不需要编辑字段 + */ + String[] COLUMNNAME_NOT_EDIT = {"id", "create_by", "create_time", "del_flag"}; + + /** + * 页面不需要显示的列表字段 + */ + String[] COLUMNNAME_NOT_LIST = {"id", "create_by", "create_time", "del_flag", "update_by", + "update_time"}; + + /** + * 页面不需要查询字段 + */ + String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by", + "update_time", "remark"}; + + /** + * Entity基类字段 + */ + String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime", "remark"}; + + /** + * Tree基类字段 + */ + String[] TREE_ENTITY = {"parentName", "parentId", "orderNum", "ancestors"}; + + /** + * 文本框 + */ + String HTML_INPUT = "input"; + + /** + * 文本域 + */ + String HTML_TEXTAREA = "textarea"; + + /** + * 下拉框 + */ + String HTML_SELECT = "select"; + + /** + * 单选框 + */ + String HTML_RADIO = "radio"; + + /** + * 复选框 + */ + String HTML_CHECKBOX = "checkbox"; + + /** + * 日期控件 + */ + String HTML_DATETIME = "datetime"; + + /** + * 图片上传控件 + */ + String HTML_IMAGE_UPLOAD = "imageUpload"; + + /** + * 文件上传控件 + */ + String HTML_FILE_UPLOAD = "fileUpload"; + + /** + * 富文本控件 + */ + String HTML_EDITOR = "editor"; + + /** + * 字符串类型 + */ + String TYPE_STRING = "String"; + + /** + * 整型 + */ + String TYPE_INTEGER = "Integer"; + + /** + * 长整型 + */ + String TYPE_LONG = "Long"; + + /** + * 浮点型 + */ + String TYPE_DOUBLE = "Double"; + + /** + * 高精度计算类型 + */ + String TYPE_BIGDECIMAL = "BigDecimal"; + + /** + * 时间类型 + */ + String TYPE_DATE = "Date"; + + /** + * 模糊查询 + */ + String QUERY_LIKE = "LIKE"; + + /** + * 相等查询 + */ + String QUERY_EQ = "EQ"; + + /** + * 需要 + */ + String REQUIRE = "1"; +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java index d07de0ffb..f63903b0c 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java @@ -137,9 +137,8 @@ public class ServletUtils extends ServletUtil { * * @param response 渲染对象 * @param string 待渲染的字符串 - * @return null */ - public static String renderString(HttpServletResponse response, String string) { + public static void renderString(HttpServletResponse response, String string) { try { response.setStatus(HttpStatus.HTTP_OK); response.setContentType(MediaType.APPLICATION_JSON_VALUE); @@ -148,7 +147,6 @@ public class ServletUtils extends ServletUtil { } catch (IOException e) { e.printStackTrace(); } - return null; } /** @@ -159,12 +157,12 @@ public class ServletUtils extends ServletUtil { public static boolean isAjaxRequest(HttpServletRequest request) { String accept = request.getHeader("accept"); - if (accept != null && accept.indexOf("application/json") != -1) { + if (accept != null && accept.contains("application/json")) { return true; } String xRequestedWith = request.getHeader("X-Requested-With"); - if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) { + if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) { return true; } @@ -174,10 +172,7 @@ public class ServletUtils extends ServletUtil { } String ajax = request.getParameter("__ajax"); - if (StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml")) { - return true; - } - return false; + return StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml"); } public static String getClientIP() { diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java index dc7346c08..317ca924f 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/BlackListUrlFilter.java @@ -1,58 +1,58 @@ -package com.ruoyi.gateway.filter; - -import com.ruoyi.gateway.utils.WebFluxUtils; -import org.springframework.cloud.gateway.filter.GatewayFilter; -import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -/** - * 黑名单过滤器 - * - * @author ruoyi - */ -@Component -public class BlackListUrlFilter extends AbstractGatewayFilterFactory { - @Override - public GatewayFilter apply(Config config) { - return (exchange, chain) -> { - - String url = exchange.getRequest().getURI().getPath(); - if (config.matchBlacklist(url)) { - return WebFluxUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问"); - } - - return chain.filter(exchange); - }; - } - - public BlackListUrlFilter() { - super(Config.class); - } - - public static class Config { - private List blacklistUrl; - - private List blacklistUrlPattern = new ArrayList<>(); - - public boolean matchBlacklist(String url) { - return blacklistUrlPattern.isEmpty() ? false : blacklistUrlPattern.stream().filter(p -> p.matcher(url).find()).findAny().isPresent(); - } - - public List getBlacklistUrl() { - return blacklistUrl; - } - - public void setBlacklistUrl(List blacklistUrl) { - this.blacklistUrl = blacklistUrl; - this.blacklistUrlPattern.clear(); - this.blacklistUrl.forEach(url -> { - this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE)); - }); - } - } - -} +package com.ruoyi.gateway.filter; + +import com.ruoyi.gateway.utils.WebFluxUtils; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * 黑名单过滤器 + * + * @author ruoyi + */ +@Component +public class BlackListUrlFilter extends AbstractGatewayFilterFactory { + @Override + public GatewayFilter apply(Config config) { + return (exchange, chain) -> { + + String url = exchange.getRequest().getURI().getPath(); + if (config.matchBlacklist(url)) { + return WebFluxUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问"); + } + + return chain.filter(exchange); + }; + } + + public BlackListUrlFilter() { + super(Config.class); + } + + public static class Config { + private List blacklistUrl; + + private List blacklistUrlPattern = new ArrayList<>(); + + public boolean matchBlacklist(String url) { + return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find()); + } + + public List getBlacklistUrl() { + return blacklistUrl; + } + + public void setBlacklistUrl(List blacklistUrl) { + this.blacklistUrl = blacklistUrl; + this.blacklistUrlPattern.clear(); + this.blacklistUrl.forEach(url -> { + this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"), Pattern.CASE_INSENSITIVE)); + }); + } + } + +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java index e6eb72b2c..e9b6af160 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/ValidateCodeFilter.java @@ -1,73 +1,73 @@ -package com.ruoyi.gateway.filter; - -import com.ruoyi.common.core.utils.JsonUtils; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.gateway.config.properties.CaptchaProperties; -import com.ruoyi.gateway.service.ValidateCodeService; -import com.ruoyi.gateway.utils.WebFluxUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.gateway.filter.GatewayFilter; -import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.core.io.buffer.DataBufferUtils; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.stereotype.Component; -import reactor.core.publisher.Flux; - -import java.nio.CharBuffer; -import java.nio.charset.StandardCharsets; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -/** - * 验证码过滤器 - * - * @author ruoyi - */ -@Component -public class ValidateCodeFilter extends AbstractGatewayFilterFactory { - private final static String[] VALIDATE_URL = new String[]{"/auth/login", "/auth/register"}; - - @Autowired - private ValidateCodeService validateCodeService; - - @Autowired - private CaptchaProperties captchaProperties; - - private static final String CODE = "code"; - - private static final String UUID = "uuid"; - - @Override - public GatewayFilter apply(Object config) { - return (exchange, chain) -> { - ServerHttpRequest request = exchange.getRequest(); - - // 非登录/注册请求或验证码关闭,不处理 - if (!StringUtils.containsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled()) { - return chain.filter(exchange); - } - - try { - String rspStr = resolveBodyFromRequest(request); - Map obj = JsonUtils.parseMap(rspStr); - validateCodeService.checkCapcha(obj.get(CODE), obj.get(UUID)); - } catch (Exception e) { - return WebFluxUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage()); - } - return chain.filter(exchange); - }; - } - - private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) { - // 获取请求体 - Flux body = serverHttpRequest.getBody(); - AtomicReference bodyRef = new AtomicReference<>(); - body.subscribe(buffer -> { - CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer()); - DataBufferUtils.release(buffer); - bodyRef.set(charBuffer.toString()); - }); - return bodyRef.get(); - } -} +package com.ruoyi.gateway.filter; + +import com.ruoyi.common.core.utils.JsonUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.gateway.config.properties.CaptchaProperties; +import com.ruoyi.gateway.service.ValidateCodeService; +import com.ruoyi.gateway.utils.WebFluxUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Flux; + +import java.nio.CharBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; + +/** + * 验证码过滤器 + * + * @author ruoyi + */ +@Component +public class ValidateCodeFilter extends AbstractGatewayFilterFactory { + private final static String[] VALIDATE_URL = new String[]{"/auth/login", "/auth/register"}; + + @Autowired + private ValidateCodeService validateCodeService; + + @Autowired + private CaptchaProperties captchaProperties; + + private static final String CODE = "code"; + + private static final String UUID = "uuid"; + + @Override + public GatewayFilter apply(Object config) { + return (exchange, chain) -> { + ServerHttpRequest request = exchange.getRequest(); + + // 非登录/注册请求或验证码关闭,不处理 + if (!StringUtils.containsAnyIgnoreCase(request.getURI().getPath(), VALIDATE_URL) || !captchaProperties.getEnabled()) { + return chain.filter(exchange); + } + + try { + String rspStr = resolveBodyFromRequest(request); + Map obj = JsonUtils.parseMap(rspStr); + validateCodeService.checkCaptcha(obj.get(CODE), obj.get(UUID)); + } catch (Exception e) { + return WebFluxUtils.webFluxResponseWriter(exchange.getResponse(), e.getMessage()); + } + return chain.filter(exchange); + }; + } + + private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) { + // 获取请求体 + Flux body = serverHttpRequest.getBody(); + AtomicReference bodyRef = new AtomicReference<>(); + body.subscribe(buffer -> { + CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer()); + DataBufferUtils.release(buffer); + bodyRef.set(charBuffer.toString()); + }); + return bodyRef.get(); + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java index 0836cdd8c..5d8bc50d5 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/filter/XssFilter.java @@ -1,110 +1,110 @@ -package com.ruoyi.gateway.filter; - -import cn.hutool.http.HtmlUtil; -import com.ruoyi.common.core.utils.StringUtils; -import com.ruoyi.gateway.config.properties.XssProperties; -import io.netty.buffer.ByteBufAllocator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.gateway.filter.GatewayFilterChain; -import org.springframework.cloud.gateway.filter.GlobalFilter; -import org.springframework.core.Ordered; -import org.springframework.core.io.buffer.*; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.http.server.reactive.ServerHttpRequest; -import org.springframework.http.server.reactive.ServerHttpRequestDecorator; -import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.nio.charset.StandardCharsets; - -/** - * 跨站脚本过滤器 - * - * @author ruoyi - */ -@Component -@ConditionalOnProperty(value = "security.xss.enabled", havingValue = "true") -public class XssFilter implements GlobalFilter, Ordered { - // 跨站脚本的 xss 配置,nacos自行添加 - @Autowired - private XssProperties xss; - - @Override - public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { - ServerHttpRequest request = exchange.getRequest(); - // GET DELETE 不过滤 - HttpMethod method = request.getMethod(); - if (method == null || method.matches("GET") || method.matches("DELETE")) { - return chain.filter(exchange); - } - // 非json类型,不过滤 - if (!isJsonRequest(exchange)) { - return chain.filter(exchange); - } - // excludeUrls 不过滤 - String url = request.getURI().getPath(); - if (StringUtils.matches(url, xss.getExcludeUrls())) { - return chain.filter(exchange); - } - ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange); - return chain.filter(exchange.mutate().request(httpRequestDecorator).build()); - - } - - private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange) { - ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) { - @Override - public Flux getBody() { - Flux body = super.getBody(); - return body.buffer().map(dataBuffers -> { - DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); - DataBuffer join = dataBufferFactory.join(dataBuffers); - byte[] content = new byte[join.readableByteCount()]; - join.read(content); - DataBufferUtils.release(join); - String bodyStr = new String(content, StandardCharsets.UTF_8); - // 防xss攻击过滤 - bodyStr = HtmlUtil.cleanHtmlTag(bodyStr); - // 转成字节 - byte[] bytes = bodyStr.getBytes(); - NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); - DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length); - buffer.write(bytes); - return buffer; - }); - } - - @Override - public HttpHeaders getHeaders() { - HttpHeaders httpHeaders = new HttpHeaders(); - httpHeaders.putAll(super.getHeaders()); - // 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length - httpHeaders.remove(HttpHeaders.CONTENT_LENGTH); - httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); - return httpHeaders; - } - - }; - return serverHttpRequestDecorator; - } - - /** - * 是否是Json请求 - * - * @param request - */ - public boolean isJsonRequest(ServerWebExchange exchange) { - String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE); - return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); - } - - @Override - public int getOrder() { - return -100; - } -} +package com.ruoyi.gateway.filter; + +import cn.hutool.http.HtmlUtil; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.gateway.config.properties.XssProperties; +import io.netty.buffer.ByteBufAllocator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.core.Ordered; +import org.springframework.core.io.buffer.*; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.nio.charset.StandardCharsets; + +/** + * 跨站脚本过滤器 + * + * @author ruoyi + */ +@Component +@ConditionalOnProperty(value = "security.xss.enabled", havingValue = "true") +public class XssFilter implements GlobalFilter, Ordered { + // 跨站脚本的 xss 配置,nacos自行添加 + @Autowired + private XssProperties xss; + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + ServerHttpRequest request = exchange.getRequest(); + // GET DELETE 不过滤 + HttpMethod method = request.getMethod(); + if (method == null || method.matches("GET") || method.matches("DELETE")) { + return chain.filter(exchange); + } + // 非json类型,不过滤 + if (!isJsonRequest(exchange)) { + return chain.filter(exchange); + } + // excludeUrls 不过滤 + String url = request.getURI().getPath(); + if (StringUtils.matches(url, xss.getExcludeUrls())) { + return chain.filter(exchange); + } + ServerHttpRequestDecorator httpRequestDecorator = requestDecorator(exchange); + return chain.filter(exchange.mutate().request(httpRequestDecorator).build()); + + } + + private ServerHttpRequestDecorator requestDecorator(ServerWebExchange exchange) { + ServerHttpRequestDecorator serverHttpRequestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) { + @Override + public Flux getBody() { + Flux body = super.getBody(); + return body.buffer().map(dataBuffers -> { + DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); + DataBuffer join = dataBufferFactory.join(dataBuffers); + byte[] content = new byte[join.readableByteCount()]; + join.read(content); + DataBufferUtils.release(join); + String bodyStr = new String(content, StandardCharsets.UTF_8); + // 防xss攻击过滤 + bodyStr = HtmlUtil.cleanHtmlTag(bodyStr); + // 转成字节 + byte[] bytes = bodyStr.getBytes(); + NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); + DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length); + buffer.write(bytes); + return buffer; + }); + } + + @Override + public HttpHeaders getHeaders() { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.putAll(super.getHeaders()); + // 由于修改了请求体的body,导致content-length长度不确定,因此需要删除原先的content-length + httpHeaders.remove(HttpHeaders.CONTENT_LENGTH); + httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); + return httpHeaders; + } + + }; + return serverHttpRequestDecorator; + } + + /** + * 是否是Json请求 + * + * @param exchange HTTP请求 + */ + public boolean isJsonRequest(ServerWebExchange exchange) { + String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE); + return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); + } + + @Override + public int getOrder() { + return -100; + } +} diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java index 23e616406..b966ab79e 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/handler/ValidateCodeHandler.java @@ -29,7 +29,7 @@ public class ValidateCodeHandler implements HandlerFunction { public Mono handle(ServerRequest serverRequest) { R> ajax; try { - ajax = validateCodeService.createCapcha(); + ajax = validateCodeService.createCaptcha(); } catch (CaptchaException | IOException e) { return Mono.error(e); } diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java index 2a8d43959..bf1cdea7b 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/ValidateCodeService.java @@ -15,10 +15,10 @@ public interface ValidateCodeService { /** * 生成验证码 */ - R> createCapcha() throws IOException, CaptchaException; + R> createCaptcha() throws IOException, CaptchaException; /** * 校验验证码 */ - void checkCapcha(String key, String value) throws CaptchaException; + void checkCaptcha(String key, String value) throws CaptchaException; } diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java index eb59a12b0..7b31a6123 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java @@ -36,7 +36,7 @@ public class ValidateCodeServiceImpl implements ValidateCodeService { * 生成验证码 */ @Override - public R> createCapcha() throws IOException, CaptchaException { + public R> createCaptcha() throws IOException, CaptchaException { Map ajax = new HashMap<>(); boolean captchaOnOff = captchaProperties.getEnabled(); ajax.put("captchaOnOff", captchaOnOff); @@ -83,7 +83,7 @@ public class ValidateCodeServiceImpl implements ValidateCodeService { * 校验验证码 */ @Override - public void checkCapcha(String code, String uuid) throws CaptchaException { + public void checkCaptcha(String code, String uuid) throws CaptchaException { if (StringUtils.isEmpty(code)) { throw new CaptchaException("验证码不能为空"); } diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java index 8532bd7bf..6e08bb0f0 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/service/GenTableServiceImpl.java @@ -293,8 +293,17 @@ public class GenTableServiceImpl implements IGenTableService { GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName()); column.setColumnId(prevColumn.getColumnId()); if (column.isList()) { - // 如果是列表,继续保留字典类型 + // 如果是列表,继续保留查询方式/字典类型选项 column.setDictType(prevColumn.getDictType()); + column.setQueryType(prevColumn.getQueryType()); + } + if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk() + && (column.isInsert() || column.isEdit()) + && ((column.isUsableColumn()) || (!column.isSuperColumn()))) + { + // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项 + column.setIsRequired(prevColumn.getIsRequired()); + column.setHtmlType(prevColumn.getHtmlType()); } genTableColumnMapper.updateById(column); } else { diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java index 3ca35ccf3..fc58a797a 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/GenUtils.java @@ -40,6 +40,7 @@ public class GenUtils { column.setJavaField(StringUtils.toCamelCase(columnName)); // 设置默认类型 column.setJavaType(GenConstants.TYPE_STRING); + column.setQueryType(GenConstants.QUERY_EQ); if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) { // 字符串长度超过500设置为文本域 @@ -130,8 +131,7 @@ public class GenUtils { public static String getModuleName(String packageName) { int lastIndex = packageName.lastIndexOf("."); int nameLength = packageName.length(); - String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength); - return moduleName; + return StringUtils.substring(packageName, lastIndex + 1, nameLength); } /** @@ -143,8 +143,7 @@ public class GenUtils { public static String getBusinessName(String tableName) { int lastIndex = tableName.lastIndexOf("_"); int nameLength = tableName.length(); - String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength); - return businessName; + return StringUtils.substring(tableName, lastIndex + 1, nameLength); } /** @@ -219,4 +218,4 @@ public class GenUtils { return 0; } } -} \ No newline at end of file +} diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java index c8fd1a451..cb99b9043 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/com/ruoyi/gen/util/VelocityUtils.java @@ -197,8 +197,7 @@ public class VelocityUtils { */ public static String getPackagePrefix(String packageName) { int lastIndex = packageName.lastIndexOf("."); - String basePackage = StringUtils.substring(packageName, 0, lastIndex); - return basePackage; + return StringUtils.substring(packageName, 0, lastIndex); } /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java index a1363e262..081f84873 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java @@ -35,7 +35,7 @@ public interface SysUserMapper extends BaseMapperPlus selectUserList(SysUser sysUser); /** - * 根据条件分页查询未已配用户角色列表 + * 根据条件分页查询已配用户角色列表 * * @param user 用户信息 * @return 用户信息集合信息 diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java index a5bfab6ec..dea1cbf7e 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java @@ -59,7 +59,6 @@ public interface ISysConfigService { * 批量删除参数信息 * * @param configIds 需要删除的参数ID - * @return 结果 */ void deleteConfigByIds(Long[] configIds); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java index 1eb4ccb51..feb16a9f1 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java @@ -44,7 +44,6 @@ public interface ISysDictDataService { * 批量删除字典数据信息 * * @param dictCodes 需要删除的字典数据ID - * @return 结果 */ void deleteDictDataByIds(Long[] dictCodes); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java index 8afd55308..facf9f752 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java @@ -13,6 +13,7 @@ import java.util.List; * @author ruoyi */ public interface ISysDictTypeService { + TableDataInfo selectPageDictTypeList(SysDictType dictType, PageQuery pageQuery); /** @@ -58,7 +59,6 @@ public interface ISysDictTypeService { * 批量删除字典信息 * * @param dictIds 需要删除的字典ID - * @return 结果 */ void deleteDictTypeByIds(Long[] dictIds); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java index 8829baa7e..96ef69454 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java @@ -34,7 +34,7 @@ public interface ISysLogininforService { * 批量删除系统登录日志 * * @param infoIds 需要删除的登录日志ID - * @return + * @return 结果 */ int deleteLogininforByIds(Long[] infoIds); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java index 7dd41e0aa..83595aea7 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java @@ -12,6 +12,7 @@ import java.util.List; * @author ruoyi */ public interface ISysPostService { + TableDataInfo selectPagePostList(SysPost post, PageQuery pageQuery); /** @@ -82,7 +83,6 @@ public interface ISysPostService { * * @param postIds 需要删除的岗位ID * @return 结果 - * @throws Exception 异常 */ int deletePostByIds(Long[] postIds); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java index 49fb61ae0..4fd193c94 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java @@ -137,7 +137,6 @@ public class SysConfigServiceImpl implements ISysConfigService { * 批量删除参数信息 * * @param configIds 需要删除的参数ID - * @return 结果 */ @Override public void deleteConfigByIds(Long[] configIds) { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java index b0e567e88..ccaf2145f 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java @@ -82,7 +82,6 @@ public class SysDictDataServiceImpl implements ISysDictDataService { * 批量删除字典数据信息 * * @param dictCodes 需要删除的字典数据ID - * @return 结果 */ @Override public void deleteDictDataByIds(Long[] dictCodes) { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java index 87d8f079b..01ebc11f1 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java @@ -125,7 +125,6 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService { * 批量删除字典类型信息 * * @param dictIds 需要删除的字典ID - * @return 结果 */ @Override public void deleteDictTypeByIds(Long[] dictIds) { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java index 94155660a..df77b9b71 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java @@ -77,7 +77,7 @@ public class SysLogininforServiceImpl implements ISysLogininforService { * 批量删除系统登录日志 * * @param infoIds 需要删除的登录日志ID - * @return + * @return 结果 */ @Override public int deleteLogininforByIds(Long[] infoIds) { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java index 487fbef26..a04ca94e5 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java @@ -415,7 +415,7 @@ public class SysMenuServiceImpl implements ISysMenuService { * 判断是否有子节点 */ private boolean hasChild(List list, SysMenu t) { - return getChildList(list, t).size() > 0 ? true : false; + return getChildList(list, t).size() > 0; } /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java index 60a55532c..860fdec3d 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java @@ -148,7 +148,6 @@ public class SysPostServiceImpl implements ISysPostService { * * @param postIds 需要删除的岗位ID * @return 结果 - * @throws Exception 异常 */ @Override public int deletePostByIds(Long[] postIds) { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java index 9a0b62049..c60864a4e 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java @@ -374,7 +374,7 @@ public class SysRoleServiceImpl implements ISysRoleService { * 批量选择授权用户角色 * * @param roleId 角色ID - * @param userIds 需要删除的用户数据ID + * @param userIds 需要授权的用户数据ID * @return 结果 */ @Override diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml index dbe451fa9..c3d70f308 100644 --- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml +++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml @@ -50,7 +50,7 @@