bean = new FilterRegistrationBean<>(filter);
bean.setOrder(order);
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java
new file mode 100644
index 000000000..559267c3f
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java
@@ -0,0 +1,80 @@
+package cn.iocoder.yudao.framework.web.core.clean;
+
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.safety.Safelist;
+
+/**
+ * jsonp 过滤字符串
+ */
+public class JsoupXssCleaner implements XssCleaner {
+
+ private final Safelist safelist;
+
+ /**
+ * 用于在 src 属性使用相对路径时,强制转换为绝对路径。 为空时不处理,值应为绝对路径的前缀(包含协议部分)
+ */
+ private final String baseUri;
+
+ /**
+ * 无参构造,默认使用 {@link JsoupXssCleaner#buildSafelist} 方法构建一个安全列表
+ */
+ public JsoupXssCleaner() {
+ this.safelist = buildSafelist();
+ this.baseUri = "";
+ }
+
+ public JsoupXssCleaner(Safelist safelist) {
+ this.safelist = safelist;
+ this.baseUri = "";
+ }
+
+ public JsoupXssCleaner(String baseUri) {
+ this.safelist = buildSafelist();
+ this.baseUri = baseUri;
+ }
+
+ public JsoupXssCleaner(Safelist safelist, String baseUri) {
+ this.safelist = safelist;
+ this.baseUri = baseUri;
+ }
+
+ /**
+ * 构建一个 Xss 清理的 Safelist 规则。
+ * 基于 Safelist#relaxed() 的基础上:
+ * 1. 扩展支持了 style 和 class 属性
+ * 2. a 标签额外支持了 target 属性
+ * 3. img 标签额外支持了 data 协议,便于支持 base64
+ *
+ * @return Safelist
+ */
+ private Safelist buildSafelist() {
+ // 使用 jsoup 提供的默认的
+ Safelist relaxedSafelist = Safelist.relaxed();
+ // 富文本编辑时一些样式是使用 style 来进行实现的
+ // 比如红色字体 style="color:red;", 所以需要给所有标签添加 style 属性
+ // 注意:style 属性会有注入风险
+ relaxedSafelist.addAttributes(":all", "style", "class");
+ // 保留 a 标签的 target 属性
+ relaxedSafelist.addAttributes("a", "target");
+ // 支持img 为base64
+ relaxedSafelist.addProtocols("img", "src", "data");
+
+ // 保留相对路径, 保留相对路径时,必须提供对应的 baseUri 属性,否则依然会被删除
+ // WHITELIST.preserveRelativeLinks(false);
+
+ // 移除 a 标签和 img 标签的一些协议限制,这会导致 xss 防注入失效,如
+ // 虽然可以重写 WhiteList#isSafeAttribute 来处理,但是有隐患,所以暂时不支持相对路径
+ // WHITELIST.removeProtocols("a", "href", "ftp", "http", "https", "mailto");
+ // WHITELIST.removeProtocols("img", "src", "http", "https");
+
+ return relaxedSafelist;
+ }
+
+ @Override
+ public String clean(String html) {
+ return Jsoup.clean(html, baseUri, safelist, new Document.OutputSettings().prettyPrint(false));
+ }
+
+}
+
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java
new file mode 100644
index 000000000..433f7e775
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java
@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.framework.web.core.clean;
+
+/**
+ * 对 html 文本中的有 Xss 风险的数据进行清理
+ */
+public interface XssCleaner {
+
+ /**
+ * 清理有 Xss 风险的文本
+ *
+ * @param html 原 html
+ * @return 清理后的 html
+ */
+ String clean(String html);
+}
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java
index 050a86cc1..2da18768d 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java
@@ -1,6 +1,7 @@
package cn.iocoder.yudao.framework.web.core.filter;
import cn.iocoder.yudao.framework.web.config.XssProperties;
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
import lombok.AllArgsConstructor;
import org.springframework.util.PathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -13,7 +14,7 @@ import java.io.IOException;
/**
* Xss 过滤器
- *
+ *
* 对 Xss 不了解的胖友,可以看看 http://www.iocoder.cn/Fight/The-new-girl-asked-me-why-AJAX-requests-are-not-secure-I-did-not-answer/
*
* @author 芋道源码
@@ -30,10 +31,12 @@ public class XssFilter extends OncePerRequestFilter {
*/
private final PathMatcher pathMatcher;
+ private final XssCleaner xssCleaner;
+
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
- filterChain.doFilter(new XssRequestWrapper(request), response);
+ filterChain.doFilter(new XssRequestWrapper(request, xssCleaner), response);
}
@Override
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java
index 25bd20978..7beed46cc 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java
@@ -1,21 +1,10 @@
package cn.iocoder.yudao.framework.web.core.filter;
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.ReflectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.http.HTMLFilter;
-import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
-import javax.servlet.ReadListener;
-import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
+import java.util.LinkedHashMap;
import java.util.Map;
/**
@@ -24,113 +13,79 @@ import java.util.Map;
* @author 芋道源码
*/
public class XssRequestWrapper extends HttpServletRequestWrapper {
+ private final XssCleaner xssCleaner;
- /**
- * 基于线程级别的 HTMLFilter 对象,因为它线程非安全
- */
- private static final ThreadLocal HTML_FILTER = ThreadLocal.withInitial(() -> {
- HTMLFilter htmlFilter = new HTMLFilter();
- // 反射修改 encodeQuotes 属性为 false,避免 " 被转移成 " 字符
- ReflectUtil.setFieldValue(htmlFilter, "encodeQuotes", false);
- return htmlFilter;
- });
-
- public XssRequestWrapper(HttpServletRequest request) {
+ public XssRequestWrapper(HttpServletRequest request, XssCleaner xssCleaner) {
super(request);
+ this.xssCleaner = xssCleaner;
}
- private static String filterXss(String content) {
- if (StrUtil.isEmpty(content)) {
- return content;
+ // ============================ parameter ============================
+ @Override
+ public Map getParameterMap() {
+ Map map = new LinkedHashMap<>();
+ Map parameters = super.getParameterMap();
+ for (Map.Entry entry : parameters.entrySet()) {
+ String[] values = entry.getValue();
+ for (int i = 0; i < values.length; i++) {
+ values[i] = xssCleaner.clean(values[i]);
+ }
+ map.put(entry.getKey(), values);
}
- return HTML_FILTER.get().filter(content);
- }
-
- // ========== IO 流相关 ==========
-
- @Override
- public BufferedReader getReader() throws IOException {
- return new BufferedReader(new InputStreamReader(this.getInputStream()));
- }
-
- @Override
- public ServletInputStream getInputStream() throws IOException {
- // 如果非 json 请求,不进行 Xss 处理
- if (!ServletUtils.isJsonRequest(this)) {
- return super.getInputStream();
- }
-
- // 读取内容,并过滤
- String content = IoUtil.readUtf8(super.getInputStream());
- content = filterXss(content);
- final ByteArrayInputStream newInputStream = new ByteArrayInputStream(content.getBytes());
- // 返回 ServletInputStream
- return new ServletInputStream() {
-
- @Override
- public int read() {
- return newInputStream.read();
- }
-
- @Override
- public boolean isFinished() {
- return true;
- }
-
- @Override
- public boolean isReady() {
- return true;
- }
-
- @Override
- public void setReadListener(ReadListener readListener) {}
-
- };
- }
-
- // ========== Param 相关 ==========
-
- @Override
- public String getParameter(String name) {
- String value = super.getParameter(name);
- return filterXss(value);
+ return map;
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
- if (ArrayUtil.isEmpty(values)) {
- return values;
+ if (values == null) {
+ return null;
}
- // 过滤处理
- for (int i = 0; i < values.length; i++) {
- values[i] = filterXss(values[i]);
+ int count = values.length;
+ String[] encodedValues = new String[count];
+ for (int i = 0; i < count; i++) {
+ encodedValues[i] = xssCleaner.clean(values[i]);
}
- return values;
+ return encodedValues;
}
@Override
- public Map getParameterMap() {
- Map valueMap = super.getParameterMap();
- if (CollUtil.isEmpty(valueMap)) {
- return valueMap;
+ public String getParameter(String name) {
+ String value = super.getParameter(name);
+ if (value == null) {
+ return null;
}
- // 过滤处理
- for (Map.Entry entry : valueMap.entrySet()) {
- String[] values = entry.getValue();
- for (int i = 0; i < values.length; i++) {
- values[i] = filterXss(values[i]);
- }
- }
- return valueMap;
+ return xssCleaner.clean(value);
}
- // ========== Header 相关 ==========
+ // ============================ attribute ============================
+ @Override
+ public Object getAttribute(String name) {
+ Object value = super.getAttribute(name);
+ if (value instanceof String) {
+ xssCleaner.clean((String) value);
+ }
+ return value;
+ }
+ // ============================ header ============================
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
- return filterXss(value);
+ if (value == null) {
+ return null;
+ }
+ return xssCleaner.clean(value);
+ }
+
+ // ============================ queryString ============================
+ @Override
+ public String getQueryString() {
+ String value = super.getQueryString();
+ if (value == null) {
+ return null;
+ }
+ return xssCleaner.clean(value);
}
}
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java
new file mode 100644
index 000000000..7e1f631c7
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java
@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.framework.web.core.json;
+
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+
+/**
+ * XSS 过滤 jackson 反序列化器。
+ * 在反序列化的过程中,会对字符串进行 XSS 过滤。
+ *
+ * @author Hccake
+ */
+@Slf4j
+@AllArgsConstructor
+public class XssStringJsonDeserializer extends StringDeserializer {
+
+ private final XssCleaner xssCleaner;
+
+ @Override
+ public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+ if (p.hasToken(JsonToken.VALUE_STRING)) {
+ return xssCleaner.clean(p.getText());
+ }
+ JsonToken t = p.currentToken();
+ // [databind#381]
+ if (t == JsonToken.START_ARRAY) {
+ return _deserializeFromArray(p, ctxt);
+ }
+ // need to gracefully handle byte[] data, as base64
+ if (t == JsonToken.VALUE_EMBEDDED_OBJECT) {
+ Object ob = p.getEmbeddedObject();
+ if (ob == null) {
+ return null;
+ }
+ if (ob instanceof byte[]) {
+ return ctxt.getBase64Variant().encode((byte[]) ob, false);
+ }
+ // otherwise, try conversion using toString()...
+ return ob.toString();
+ }
+ // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
+ if (t == JsonToken.START_OBJECT) {
+ return ctxt.extractScalarFromObject(p, this, _valueClass);
+ }
+
+ if (t.isScalarValue()) {
+ String text = p.getValueAsString();
+ return xssCleaner.clean(text);
+ }
+ return (String) ctxt.handleUnexpectedToken(_valueClass, p);
+ }
+}
+
diff --git a/yudao-gateway/pom.xml b/yudao-gateway/pom.xml
index 45ebc2ece..a0a03fd6d 100644
--- a/yudao-gateway/pom.xml
+++ b/yudao-gateway/pom.xml
@@ -46,7 +46,7 @@
com.github.xiaoymin
- knife4j-spring-boot-starter
+ knife4j-openapi2-spring-boot-starter
io.swagger
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java
index b0df3e34f..1d286c52f 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java
@@ -11,9 +11,11 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import org.apache.ibatis.type.JdbcType;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
+import org.mapstruct.Named;
import org.mapstruct.factory.Mappers;
import java.util.List;
@@ -37,7 +39,7 @@ public interface CodegenConvert {
@Mappings({
@Mapping(source = "name", target = "columnName"),
- @Mapping(source = "type", target = "dataType"),
+ @Mapping(source = "metaInfo.jdbcType", target = "dataType", qualifiedByName = "getDataType"),
@Mapping(source = "comment", target = "columnComment"),
@Mapping(source = "metaInfo.nullable", target = "nullable"),
@Mapping(source = "keyFlag", target = "primaryKey"),
@@ -47,6 +49,11 @@ public interface CodegenConvert {
})
CodegenColumnDO convert(TableField bean);
+ @Named("getDataType")
+ default String getDataType(JdbcType jdbcType) {
+ return jdbcType.name();
+ }
+
// ========== CodegenTableDO 相关 ==========
// List convertList02(List list);
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java
index 4e7f330e5..f1990f3fc 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnListConditionEnu
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.generator.config.po.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@@ -29,7 +30,7 @@ public class CodegenColumnDO extends BaseDO {
private Long id;
/**
* 表编号
- *
+ *
* 关联 {@link CodegenTableDO#getId()}
*/
private Long tableId;
@@ -41,7 +42,8 @@ public class CodegenColumnDO extends BaseDO {
*/
private String columnName;
/**
- * 字段类型
+ * 数据库字段类型
+ * 关联 {@link TableField.MetaInfo#getJdbcType()}
*/
private String dataType;
/**
@@ -69,7 +71,7 @@ public class CodegenColumnDO extends BaseDO {
/**
* Java 属性类型
- *
+ *
* 例如说 String、Boolean 等等
*/
private String javaType;
@@ -79,7 +81,7 @@ public class CodegenColumnDO extends BaseDO {
private String javaField;
/**
* 字典类型
- *
+ *
* 关联 DictTypeDO 的 type 属性
*/
private String dictType;
@@ -104,7 +106,7 @@ public class CodegenColumnDO extends BaseDO {
private Boolean listOperation;
/**
* List 查询操作的条件类型
- *
+ *
* 枚举 {@link CodegenColumnListConditionEnum}
*/
private String listOperationCondition;
@@ -117,7 +119,7 @@ public class CodegenColumnDO extends BaseDO {
/**
* 显示类型
- *
+ *
* 枚举 {@link CodegenColumnHtmlTypeEnum}
*/
private String htmlType;
diff --git a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java
index 41b1dae33..a6de8d9ee 100644
--- a/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java
+++ b/yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java
@@ -1,7 +1,7 @@
package cn.iocoder.yudao.module.infra.service;
import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.generator.IDatabaseQuery.DefaultDatabaseQuery;
+import com.baomidou.mybatisplus.generator.query.DefaultQuery;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
@@ -19,7 +19,7 @@ public class DefaultDatabaseQueryTest {
ConfigBuilder builder = new ConfigBuilder(null, dataSourceConfig, null, null, null, null);
- DefaultDatabaseQuery query = new DefaultDatabaseQuery(builder);
+ DefaultQuery query = new DefaultQuery(builder);
long time = System.currentTimeMillis();
List tableInfos = query.queryTables();
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java
index 79046e984..9921c8ea8 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/captcha/CaptchaController.java
@@ -1,8 +1,11 @@
package cn.iocoder.yudao.module.system.controller.admin.captcha;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
-import com.anji.captcha.model.common.ResponseModel;
-import com.anji.captcha.model.vo.CaptchaVO;
+import com.xingyuv.captcha.model.common.ResponseModel;
+import com.xingyuv.captcha.model.vo.CaptchaVO;
+import com.xingyuv.captcha.service.CaptchaService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
@@ -10,38 +13,49 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
+import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletRequest;
/**
* 验证码
*
- * 问题:为什么不直接使用 anji 提供的 CaptchaController,而要另外继承?
- * 回答:管理使用 /admin-api/* 作为前缀,所以需要继承!
- *
* @author 芋道源码
*/
@Api(tags = "管理后台 - 验证码")
@RestController("adminCaptchaController")
@RequestMapping("/system/captcha")
-public class CaptchaController extends com.anji.captcha.controller.CaptchaController {
+public class CaptchaController {
- @PostMapping("/get")
+ @Resource
+ private CaptchaService captchaService;
+
+ @PostMapping({"/get"})
@ApiOperation("获得验证码")
@PermitAll
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
- @Override
public ResponseModel get(@RequestBody CaptchaVO data, HttpServletRequest request) {
- return super.get(data, request);
+ assert request.getRemoteHost() != null;
+ data.setBrowserInfo(getRemoteId(request));
+ return captchaService.get(data);
}
@PostMapping("/check")
@ApiOperation("校验验证码")
@PermitAll
@OperateLog(enable = false) // 避免 Post 请求被记录操作日志
- @Override
public ResponseModel check(@RequestBody CaptchaVO data, HttpServletRequest request) {
- return super.check(data, request);
+ data.setBrowserInfo(getRemoteId(request));
+ return captchaService.check(data);
+ }
+
+ public static String getRemoteId(HttpServletRequest request) {
+ String ip = ServletUtil.getClientIP(request);
+ String ua = request.getHeader("user-agent");
+ if (StrUtil.isNotBlank(ip)) {
+ return ip + ua;
+ }
+ return request.getRemoteAddr() + ua;
}
}
diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
index ad1260500..045e3bf4b 100644
--- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
+++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
@@ -22,9 +22,9 @@ import cn.iocoder.yudao.module.system.service.member.MemberService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
-import com.anji.captcha.model.common.ResponseModel;
-import com.anji.captcha.model.vo.CaptchaVO;
-import com.anji.captcha.service.CaptchaService;
+import com.xingyuv.captcha.model.common.ResponseModel;
+import com.xingyuv.captcha.model.vo.CaptchaVO;
+import com.xingyuv.captcha.service.CaptchaService;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java
index 902c4c887..b52ff9a8f 100644
--- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java
+++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImplTest.java
@@ -14,7 +14,7 @@ import cn.iocoder.yudao.module.system.service.member.MemberService;
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
import cn.iocoder.yudao.module.system.service.social.SocialUserService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
-import com.anji.captcha.service.CaptchaService;
+import com.xingyuv.captcha.service.CaptchaService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;