m = new HashMap();
- Arrays.stream(jsonStr
- .replaceFirst(",\\{", "\\{")
- .replaceFirst("\\{", "")
- .replaceFirst("\\}", "")
- .replaceAll("\"", "")
- .split(",")).forEach(item -> {
- m.put(item.split(":")[0], item.split(":")[1]);
- });
- //PointVO d = new PointVO();
- setX(Double.valueOf("" + m.get("x")).intValue());
- setY(Double.valueOf("" + m.get("y")).intValue());
- setSecretKey(m.getOrDefault("secretKey", "") + "");
- return this;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- PointVO pointVO = (PointVO) o;
- return x == pointVO.x && y == pointVO.y && Objects.equals(secretKey, pointVO.secretKey);
- }
-
- @Override
- public int hashCode() {
-
- return Objects.hash(secretKey, x, y);
- }
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/properties/AjCaptchaProperties.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/properties/AjCaptchaProperties.java
deleted file mode 100644
index 73ca016f6..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/properties/AjCaptchaProperties.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.anji.captcha.properties;
-
-import com.anji.captcha.model.common.CaptchaTypeEnum;
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-import java.awt.*;
-
-@Data
-@ConfigurationProperties(AjCaptchaProperties.PREFIX)
-public class AjCaptchaProperties {
- public static final String PREFIX = "aj.captcha";
-
- /**
- * 验证码类型.
- */
- private CaptchaTypeEnum type = CaptchaTypeEnum.DEFAULT;
-
- /**
- * 滑动拼图底图路径.
- */
- private String jigsaw = "";
-
- /**
- * 点选文字底图路径.
- */
- private String picClick = "";
-
-
- /**
- * 右下角水印文字(我的水印).
- */
- private String waterMark = "我的水印";
-
- /**
- * 右下角水印字体(文泉驿正黑).
- */
- private String waterFont = "WenQuanZhengHei.ttf";
-
- /**
- * 点选文字验证码的文字字体(文泉驿正黑).
- */
- private String fontType = "WenQuanZhengHei.ttf";
-
- /**
- * 校验滑动拼图允许误差偏移量(默认5像素).
- */
- private String slipOffset = "5";
-
- /**
- * aes加密坐标开启或者禁用(true|false).
- */
- private Boolean aesStatus = true;
-
- /**
- * 滑块干扰项(0/1/2)
- */
- private String interferenceOptions = "0";
-
- /**
- * local缓存的阈值
- */
- private String cacheNumber = "1000";
-
- /**
- * 定时清理过期local缓存(单位秒)
- */
- private String timingClear = "180";
-
- /**
- * 缓存类型redis/local/....
- */
- private StorageType cacheType = StorageType.local;
- /**
- * 历史数据清除开关
- */
- private boolean historyDataClearEnable = false;
-
- /**
- * 一分钟内接口请求次数限制 开关
- */
- private boolean reqFrequencyLimitEnable = false;
-
- /***
- * 一分钟内check接口失败次数
- */
- private int reqGetLockLimit = 5;
- /**
- *
- */
- private int reqGetLockSeconds = 300;
-
- /***
- * get接口一分钟内限制访问数
- */
- private int reqGetMinuteLimit = 100;
- private int reqCheckMinuteLimit = 100;
- private int reqVerifyMinuteLimit = 100;
-
- /**
- * 点选字体样式
- */
- private int fontStyle = Font.BOLD;
-
- /**
- * 点选字体大小
- */
- private int fontSize = 25;
-
- /**
- * 点选文字个数,存在问题,暂不要使用
- */
- private int clickWordCount = 4;
-
- public boolean getReqFrequencyLimitEnable() {
- return reqFrequencyLimitEnable;
- }
-
- public enum StorageType {
- /**
- * 内存.
- */
- local,
- /**
- * redis.
- */
- redis,
- /**
- * 其他.
- */
- other,
- }
-
- public static String getPrefix() {
- return PREFIX;
- }
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/CaptchaCacheService.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/CaptchaCacheService.java
deleted file mode 100644
index 55c662a8f..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/CaptchaCacheService.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *Copyright © 2018 anji-plus
- *安吉加加信息技术有限公司
- *http://www.anji-plus.com
- *All rights reserved.
- */
-package com.anji.captcha.service;
-
-/**
- * 验证码缓存接口
- *
- * @author lide1202@hotmail.com
- * @date 2018-08-21
- */
-public interface CaptchaCacheService {
-
- void set(String key, String value, long expiresInSeconds);
-
- boolean exists(String key);
-
- void delete(String key);
-
- String get(String key);
-
- /**
- * 缓存类型-local/redis/memcache/..
- * 通过java SPI机制,接入方可自定义实现类
- *
- * @return
- */
- String type();
-
- /***
- *
- * @param key
- * @param val
- * @return
- */
- default Long increment(String key, long val) {
- return 0L;
- }
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/CaptchaService.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/CaptchaService.java
deleted file mode 100644
index b9db2fbe2..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/CaptchaService.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *Copyright © 2018 anji-plus
- *安吉加加信息技术有限公司
- *http://www.anji-plus.com
- *All rights reserved.
- */
-package com.anji.captcha.service;
-
-import com.anji.captcha.model.common.ResponseModel;
-import com.anji.captcha.model.vo.CaptchaVO;
-
-import java.util.Properties;
-
-/**
- * 验证码服务接口
- *
- * @author lide1202@hotmail.com
- * @date 2020-05-12
- */
-public interface CaptchaService {
- /**
- * 配置初始化
- */
- void init(Properties config);
-
- /**
- * 获取验证码
- *
- * @param captchaVO
- * @return
- */
- ResponseModel get(CaptchaVO captchaVO);
-
- /**
- * 核对验证码(前端)
- *
- * @param captchaVO
- * @return
- */
- ResponseModel check(CaptchaVO captchaVO);
-
- /**
- * 二次校验验证码(后端)
- *
- * @param captchaVO
- * @return
- */
- ResponseModel verification(CaptchaVO captchaVO);
-
- /***
- * 验证码类型
- * 通过java SPI机制,接入方可自定义实现类,实现新的验证类型
- * @return
- */
- String captchaType();
-
- /**
- * 历史资源清除(过期的图片文件,生成的临时图片...)
- *
- * @param config 配置项 控制资源清理的粒度
- */
- void destroy(Properties config);
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/AbstractCaptchaService.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/AbstractCaptchaService.java
deleted file mode 100644
index a7cda707f..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/AbstractCaptchaService.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- *Copyright © 2018 anji-plus
- *安吉加加信息技术有限公司
- *http://www.anji-plus.com
- *All rights reserved.
- */
-package com.anji.captcha.service.impl;
-
-import cn.hutool.core.util.StrUtil;
-import com.anji.captcha.model.common.Const;
-import com.anji.captcha.model.common.RepCodeEnum;
-import com.anji.captcha.model.common.ResponseModel;
-import com.anji.captcha.model.vo.CaptchaVO;
-import com.anji.captcha.service.CaptchaCacheService;
-import com.anji.captcha.service.CaptchaService;
-import com.anji.captcha.service.impl.CaptchaServiceFactory;
-import com.anji.captcha.service.impl.FrequencyLimitHandler;
-import com.anji.captcha.util.AESUtil;
-import com.anji.captcha.util.CacheUtil;
-import com.anji.captcha.util.ImageUtils;
-import com.anji.captcha.util.MD5Util;
-import lombok.extern.slf4j.Slf4j;
-
-import java.awt.*;
-import java.io.File;
-import java.io.OutputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.util.Base64;
-import java.util.Objects;
-import java.util.Properties;
-
-/**
- * Created by raodeming on 2019/12/25.
- */
-@Slf4j
-public abstract class AbstractCaptchaService implements CaptchaService {
-
- protected static final String IMAGE_TYPE_PNG = "png";
-
- protected static int HAN_ZI_SIZE = 25;
-
- protected static int HAN_ZI_SIZE_HALF = HAN_ZI_SIZE / 2;
- //check校验坐标
- protected static String REDIS_CAPTCHA_KEY = "RUNNING:CAPTCHA:%s";
-
- //后台二次校验坐标
- protected static String REDIS_SECOND_CAPTCHA_KEY = "RUNNING:CAPTCHA:second-%s";
-
- protected static Long EXPIRESIN_SECONDS = 2 * 60L;
-
- protected static Long EXPIRESIN_THREE = 3 * 60L;
-
- protected static String waterMark = "我的水印";
-
- protected static String waterMarkFontStr = "WenQuanZhengHei.ttf";
-
- protected Font waterMarkFont;//水印字体
-
- protected static String slipOffset = "5";
-
- protected static Boolean captchaAesStatus = true;
-
- protected static String clickWordFontStr = "WenQuanZhengHei.ttf";
-
- protected Font clickWordFont;//点选文字字体
-
- protected static String cacheType = "local";
-
- protected static int captchaInterferenceOptions = 0;
-
- //判断应用是否实现了自定义缓存,没有就使用内存
- @Override
- public void init(final Properties config) {
- //初始化底图
- boolean aBoolean = Boolean.parseBoolean(config.getProperty(Const.CAPTCHA_INIT_ORIGINAL));
- if (!aBoolean) {
- ImageUtils.cacheImage(config.getProperty(Const.ORIGINAL_PATH_JIGSAW),
- config.getProperty(Const.ORIGINAL_PATH_PIC_CLICK));
- }
- log.info("--->>>初始化验证码底图<<<---" + captchaType());
- waterMark = config.getProperty(Const.CAPTCHA_WATER_MARK, "我的水印");
- slipOffset = config.getProperty(Const.CAPTCHA_SLIP_OFFSET, "5");
- waterMarkFontStr = config.getProperty(Const.CAPTCHA_WATER_FONT, "WenQuanZhengHei.ttf");
- captchaAesStatus = Boolean.parseBoolean(config.getProperty(Const.CAPTCHA_AES_STATUS, "true"));
- clickWordFontStr = config.getProperty(Const.CAPTCHA_FONT_TYPE, "WenQuanZhengHei.ttf");
- //clickWordFontStr = config.getProperty(Const.CAPTCHA_FONT_TYPE, "SourceHanSansCN-Normal.otf");
- cacheType = config.getProperty(Const.CAPTCHA_CACHETYPE, "local");
- captchaInterferenceOptions = Integer.parseInt(
- config.getProperty(Const.CAPTCHA_INTERFERENCE_OPTIONS, "0"));
-
- // 部署在linux中,如果没有安装中文字段,水印和点选文字,中文无法显示,
- // 通过加载resources下的font字体解决,无需在linux中安装字体
- loadWaterMarkFont();
-
- if ("local".equals(cacheType)) {
- log.info("初始化local缓存...");
- CacheUtil.init(Integer.parseInt(config.getProperty(Const.CAPTCHA_CACAHE_MAX_NUMBER, "1000")),
- Long.parseLong(config.getProperty(Const.CAPTCHA_TIMING_CLEAR_SECOND, "180")));
- }
- if ("1".equals(config.getProperty(Const.HISTORY_DATA_CLEAR_ENABLE, "0"))) {
- log.info("历史资源清除开关...开启..." + captchaType());
- Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
- @Override
- public void run() {
- destroy(config);
- }
- }));
- }
- if ("1".equals(config.getProperty(Const.REQ_FREQUENCY_LIMIT_ENABLE, "0"))) {
- if (limitHandler == null) {
- log.info("接口分钟内限流开关...开启...");
- limitHandler = new com.anji.captcha.service.impl.FrequencyLimitHandler.DefaultLimitHandler(config, getCacheService(cacheType));
- }
- }
- }
-
- protected CaptchaCacheService getCacheService(String cacheType) {
- return CaptchaServiceFactory.getCache(cacheType);
- }
-
- @Override
- public void destroy(Properties config) {
-
- }
-
- private static com.anji.captcha.service.impl.FrequencyLimitHandler limitHandler;
-
- @Override
- public ResponseModel get(CaptchaVO captchaVO) {
- if (limitHandler != null) {
- captchaVO.setClientUid(getValidateClientId(captchaVO));
- return limitHandler.validateGet(captchaVO);
- }
- return null;
- }
-
- @Override
- public ResponseModel check(CaptchaVO captchaVO) {
- if (limitHandler != null) {
- // 验证客户端
- /* ResponseModel ret = limitHandler.validateCheck(captchaVO);
- if(!validatedReq(ret)){
- return ret;
- }
- // 服务端参数验证*/
- captchaVO.setClientUid(getValidateClientId(captchaVO));
- return limitHandler.validateCheck(captchaVO);
- }
- return null;
- }
-
- @Override
- public ResponseModel verification(CaptchaVO captchaVO) {
- if (captchaVO == null) {
- return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
- }
- if (StrUtil.isEmpty(captchaVO.getCaptchaVerification())) {
- return RepCodeEnum.NULL_ERROR.parseError("captchaVerification");
- }
- if (limitHandler != null) {
- return limitHandler.validateVerify(captchaVO);
- }
- return null;
- }
-
- protected boolean validatedReq(ResponseModel resp) {
- return resp == null || resp.isSuccess();
- }
-
- protected String getValidateClientId(CaptchaVO req) {
- // 以服务端获取的客户端标识 做识别标志
- if (StrUtil.isNotEmpty(req.getBrowserInfo())) {
- return MD5Util.md5(req.getBrowserInfo());
- }
- // 以客户端Ui组件id做识别标志
- if (StrUtil.isNotEmpty(req.getClientUid())) {
- return req.getClientUid();
- }
- return null;
- }
-
- protected void afterValidateFail(CaptchaVO data) {
- if (limitHandler != null) {
- // 验证失败 分钟内计数
- String fails = String.format(FrequencyLimitHandler.LIMIT_KEY, "FAIL", data.getClientUid());
- CaptchaCacheService cs = getCacheService(cacheType);
- if (!cs.exists(fails)) {
- cs.set(fails, "1", 60);
- }
- cs.increment(fails, 1);
- }
- }
-
- /**
- * 加载resources下的font字体,add by lide1202@hotmail.com
- * 部署在linux中,如果没有安装中文字段,水印和点选文字,中文无法显示,
- * 通过加载resources下的font字体解决,无需在linux中安装字体
- */
- private void loadWaterMarkFont() {
- try {
- if (waterMarkFontStr.toLowerCase().endsWith(".ttf") || waterMarkFontStr.toLowerCase().endsWith(".ttc")
- || waterMarkFontStr.toLowerCase().endsWith(".otf")) {
- this.waterMarkFont = Font.createFont(Font.TRUETYPE_FONT,
- Objects.requireNonNull(getClass().getResourceAsStream("/fonts/" + waterMarkFontStr)))
- .deriveFont(Font.BOLD, HAN_ZI_SIZE / 2);
- } else {
- this.waterMarkFont = new Font(waterMarkFontStr, Font.BOLD, HAN_ZI_SIZE / 2);
- }
-
- } catch (Exception e) {
- log.error("load font error:{}", e);
- }
- }
-
- public static boolean base64StrToImage(String imgStr, String path) {
- if (imgStr == null) {
- return false;
- }
-
- Base64.Decoder decoder = Base64.getDecoder();
- try {
- // 解密
- byte[] b = decoder.decode(imgStr);
- // 处理数据
- for (int i = 0; i < b.length; ++i) {
- if (b[i] < 0) {
- b[i] += 256;
- }
- }
- //文件夹不存在则自动创建
- File tempFile = new File(path);
- if (!tempFile.getParentFile().exists()) {
- tempFile.getParentFile().mkdirs();
- }
- OutputStream out = Files.newOutputStream(tempFile.toPath());
- out.write(b);
- out.flush();
- out.close();
- return true;
- } catch (Exception e) {
- return false;
- }
- }
-
- /**
- * 解密前端坐标aes加密
- *
- * @param point
- * @return
- * @throws Exception
- */
- public static String decrypt(String point, String key) throws Exception {
- return AESUtil.aesDecrypt(point, key);
- }
-
- protected static int getEnOrChLength(String s) {
- int enCount = 0;
- int chCount = 0;
- for (int i = 0; i < s.length(); i++) {
- int length = String.valueOf(s.charAt(i)).getBytes(StandardCharsets.UTF_8).length;
- if (length > 1) {
- chCount++;
- } else {
- enCount++;
- }
- }
- int chOffset = (HAN_ZI_SIZE / 2) * chCount + 5;
- int enOffset = enCount * 8;
- return chOffset + enOffset;
- }
-
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/BlockPuzzleCaptchaServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/BlockPuzzleCaptchaServiceImpl.java
deleted file mode 100644
index 8417dd204..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/BlockPuzzleCaptchaServiceImpl.java
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- *Copyright © 2018 anji-plus
- *安吉加加信息技术有限公司
- *http://www.anji-plus.com
- *All rights reserved.
- */
-package com.anji.captcha.service.impl;
-
-import cn.hutool.core.util.StrUtil;
-import com.anji.captcha.model.common.CaptchaTypeEnum;
-import com.anji.captcha.model.common.RepCodeEnum;
-import com.anji.captcha.model.common.ResponseModel;
-import com.anji.captcha.model.vo.CaptchaVO;
-import com.anji.captcha.model.vo.PointVO;
-import com.anji.captcha.service.impl.AbstractCaptchaService;
-import com.anji.captcha.service.impl.CaptchaServiceFactory;
-import com.anji.captcha.util.AESUtil;
-import com.anji.captcha.util.ImageUtils;
-import com.anji.captcha.util.JsonUtil;
-import com.anji.captcha.util.RandomUtils;
-import lombok.extern.slf4j.Slf4j;
-
-import javax.imageio.ImageIO;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.io.ByteArrayOutputStream;
-import java.util.Base64;
-import java.util.Objects;
-import java.util.Properties;
-import java.util.Random;
-
-/**
- * 滑动验证码
- *
- * Created by raodeming on 2019/12/25.
- */
-@Slf4j
-public class BlockPuzzleCaptchaServiceImpl extends AbstractCaptchaService {
-
- @Override
- public void init(Properties config) {
- super.init(config);
- }
-
- @Override
- public void destroy(Properties config) {
- log.info("start-clear-history-data-", captchaType());
- }
-
- @Override
- public String captchaType() {
- return CaptchaTypeEnum.BLOCKPUZZLE.getCodeValue();
- }
-
- @Override
- public ResponseModel get(CaptchaVO captchaVO) {
- ResponseModel r = super.get(captchaVO);
- if (!validatedReq(r)) {
- return r;
- }
- //原生图片
- BufferedImage originalImage = ImageUtils.getOriginal();
- if (null == originalImage) {
- log.error("滑动底图未初始化成功,请检查路径");
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_BASEMAP_NULL);
- }
- //设置水印
- Graphics backgroundGraphics = originalImage.getGraphics();
- int width = originalImage.getWidth();
- int height = originalImage.getHeight();
- backgroundGraphics.setFont(waterMarkFont);
- backgroundGraphics.setColor(Color.white);
- backgroundGraphics.drawString(waterMark, width - getEnOrChLength(waterMark), height - (HAN_ZI_SIZE / 2) + 7);
-
- //抠图图片
- String jigsawImageBase64 = ImageUtils.getslidingBlock();
- BufferedImage jigsawImage = ImageUtils.getBase64StrToImage(jigsawImageBase64);
- if (null == jigsawImage) {
- log.error("滑动底图未初始化成功,请检查路径");
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_BASEMAP_NULL);
- }
- CaptchaVO captcha = pictureTemplatesCut(originalImage, jigsawImage, jigsawImageBase64);
- if (captcha == null
- || StrUtil.isBlank(captcha.getJigsawImageBase64())
- || StrUtil.isBlank(captcha.getOriginalImageBase64())) {
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_ERROR);
- }
- return ResponseModel.successData(captcha);
- }
-
- @Override
- public ResponseModel check(CaptchaVO captchaVO) {
- ResponseModel r = super.check(captchaVO);
- if (!validatedReq(r)) {
- return r;
- }
- //取坐标信息
- String codeKey = String.format(REDIS_CAPTCHA_KEY, captchaVO.getToken());
- if (!com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_INVALID);
- }
- String s = com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).get(codeKey);
- //验证码只用一次,即刻失效
- com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
- PointVO point = null;
- PointVO point1 = null;
- String pointJson = null;
- try {
- point = JsonUtil.parseObject(s, PointVO.class);
- //aes解密
- pointJson = decrypt(captchaVO.getPointJson(), point.getSecretKey());
- point1 = JsonUtil.parseObject(pointJson, PointVO.class);
- } catch (Exception e) {
- log.error("验证码坐标解析失败", e);
- afterValidateFail(captchaVO);
- return ResponseModel.errorMsg(e.getMessage());
- }
- if (point.x - Integer.parseInt(slipOffset) > point1.x
- || point1.x > point.x + Integer.parseInt(slipOffset)
- || point.y != point1.y) {
- afterValidateFail(captchaVO);
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_COORDINATE_ERROR);
- }
- //校验成功,将信息存入缓存
- String secretKey = point.getSecretKey();
- String value = null;
- try {
- value = AESUtil.aesEncrypt(captchaVO.getToken().concat("---").concat(pointJson), secretKey);
- } catch (Exception e) {
- log.error("AES加密失败", e);
- afterValidateFail(captchaVO);
- return ResponseModel.errorMsg(e.getMessage());
- }
- String secondKey = String.format(REDIS_SECOND_CAPTCHA_KEY, value);
- com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).set(secondKey, captchaVO.getToken(), EXPIRESIN_THREE);
- captchaVO.setResult(true);
- captchaVO.resetClientFlag();
- return ResponseModel.successData(captchaVO);
- }
-
- @Override
- public ResponseModel verification(CaptchaVO captchaVO) {
- ResponseModel r = super.verification(captchaVO);
- if (!validatedReq(r)) {
- return r;
- }
- try {
- String codeKey = String.format(REDIS_SECOND_CAPTCHA_KEY, captchaVO.getCaptchaVerification());
- if (!com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_INVALID);
- }
- //二次校验取值后,即刻失效
- com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
- } catch (Exception e) {
- log.error("验证码坐标解析失败", e);
- return ResponseModel.errorMsg(e.getMessage());
- }
- return ResponseModel.success();
- }
-
- /**
- * 根据模板切图
- *
- * @throws Exception
- */
- public CaptchaVO pictureTemplatesCut(BufferedImage originalImage, BufferedImage jigsawImage, String jigsawImageBase64) {
- try {
- CaptchaVO dataVO = new CaptchaVO();
-
- int originalWidth = originalImage.getWidth();
- int originalHeight = originalImage.getHeight();
- int jigsawWidth = jigsawImage.getWidth();
- int jigsawHeight = jigsawImage.getHeight();
-
- //随机生成拼图坐标
- PointVO point = generateJigsawPoint(originalWidth, originalHeight, jigsawWidth, jigsawHeight);
- int x = point.getX();
- int y = point.getY();
-
- //生成新的拼图图像
- BufferedImage newJigsawImage = new BufferedImage(jigsawWidth, jigsawHeight, jigsawImage.getType());
- Graphics2D graphics = newJigsawImage.createGraphics();
-
- int bold = 5;
- //如果需要生成RGB格式,需要做如下配置,Transparency 设置透明
- newJigsawImage = graphics.getDeviceConfiguration().createCompatibleImage(jigsawWidth, jigsawHeight, Transparency.TRANSLUCENT);
- // 新建的图像根据模板颜色赋值,源图生成遮罩
- cutByTemplate(originalImage, jigsawImage, newJigsawImage, x, 0);
- if (captchaInterferenceOptions > 0) {
- int position = 0;
- if (originalWidth - x - 5 > jigsawWidth * 2) {
- //在原扣图右边插入干扰图
- position = RandomUtils.getRandomInt(x + jigsawWidth + 5, originalWidth - jigsawWidth);
- } else {
- //在原扣图左边插入干扰图
- position = RandomUtils.getRandomInt(100, x - jigsawWidth - 5);
- }
- while (true) {
- String s = ImageUtils.getslidingBlock();
- if (!jigsawImageBase64.equals(s)) {
- interferenceByTemplate(originalImage, Objects.requireNonNull(ImageUtils.getBase64StrToImage(s)), position, 0);
- break;
- }
- }
- }
- if (captchaInterferenceOptions > 1) {
- while (true) {
- String s = ImageUtils.getslidingBlock();
- if (!jigsawImageBase64.equals(s)) {
- Integer randomInt = RandomUtils.getRandomInt(jigsawWidth, 100 - jigsawWidth);
- interferenceByTemplate(originalImage, Objects.requireNonNull(ImageUtils.getBase64StrToImage(s)),
- randomInt, 0);
- break;
- }
- }
- }
-
-
- // 设置“抗锯齿”的属性
- graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- graphics.setStroke(new BasicStroke(bold, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
- graphics.drawImage(newJigsawImage, 0, 0, null);
- graphics.dispose();
-
- ByteArrayOutputStream os = new ByteArrayOutputStream();//新建流。
- ImageIO.write(newJigsawImage, IMAGE_TYPE_PNG, os);//利用ImageIO类提供的write方法,将bi以png图片的数据模式写入流。
- byte[] jigsawImages = os.toByteArray();
-
- ByteArrayOutputStream oriImagesOs = new ByteArrayOutputStream();//新建流。
- ImageIO.write(originalImage, IMAGE_TYPE_PNG, oriImagesOs);//利用ImageIO类提供的write方法,将bi以jpg图片的数据模式写入流。
- byte[] oriCopyImages = oriImagesOs.toByteArray();
- Base64.Encoder encoder = Base64.getEncoder();
- dataVO.setOriginalImageBase64(encoder.encodeToString(oriCopyImages).replaceAll("\r|\n", ""));
- //point信息不传到前端,只做后端check校验
-// dataVO.setPoint(point);
- dataVO.setJigsawImageBase64(encoder.encodeToString(jigsawImages).replaceAll("\r|\n", ""));
- dataVO.setToken(RandomUtils.getUUID());
- dataVO.setSecretKey(point.getSecretKey());
-// base64StrToImage(encoder.encodeToString(oriCopyImages), "D:\\原图.png");
-// base64StrToImage(encoder.encodeToString(jigsawImages), "D:\\滑动.png");
-
- //将坐标信息存入redis中
- String codeKey = String.format(REDIS_CAPTCHA_KEY, dataVO.getToken());
- CaptchaServiceFactory.getCache(cacheType).set(codeKey, JsonUtil.toJSONString(point), EXPIRESIN_SECONDS);
- log.debug("token:{},point:{}", dataVO.getToken(), JsonUtil.toJSONString(point));
- return dataVO;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
-
- /**
- * 随机生成拼图坐标
- *
- * @param originalWidth
- * @param originalHeight
- * @param jigsawWidth
- * @param jigsawHeight
- * @return
- */
- private static PointVO generateJigsawPoint(int originalWidth, int originalHeight, int jigsawWidth, int jigsawHeight) {
- Random random = new Random();
- int widthDifference = originalWidth - jigsawWidth;
- int heightDifference = originalHeight - jigsawHeight;
- int x, y = 0;
- if (widthDifference <= 0) {
- x = 5;
- } else {
- x = random.nextInt(originalWidth - jigsawWidth - 100) + 100;
- }
- if (heightDifference <= 0) {
- y = 5;
- } else {
- y = random.nextInt(originalHeight - jigsawHeight) + 5;
- }
- String key = null;
- if (captchaAesStatus) {
- key = AESUtil.getKey();
- }
- return new PointVO(x, y, key);
- }
-
- /**
- * @param oriImage 原图
- * @param templateImage 模板图
- * @param newImage 新抠出的小图
- * @param x 随机扣取坐标X
- * @param y 随机扣取坐标y
- * @throws Exception
- */
- private static void cutByTemplate(BufferedImage oriImage, BufferedImage templateImage, BufferedImage newImage, int x, int y) {
- //临时数组遍历用于高斯模糊存周边像素值
- int[][] martrix = new int[3][3];
- int[] values = new int[9];
-
- int xLength = templateImage.getWidth();
- int yLength = templateImage.getHeight();
- // 模板图像宽度
- for (int i = 0; i < xLength; i++) {
- // 模板图片高度
- for (int j = 0; j < yLength; j++) {
- // 如果模板图像当前像素点不是透明色 copy源文件信息到目标图片中
- int rgb = templateImage.getRGB(i, j);
- if (rgb < 0) {
- newImage.setRGB(i, j, oriImage.getRGB(x + i, y + j));
-
- //抠图区域高斯模糊
- readPixel(oriImage, x + i, y + j, values);
- fillMatrix(martrix, values);
- oriImage.setRGB(x + i, y + j, avgMatrix(martrix));
- }
-
- //防止数组越界判断
- if (i == (xLength - 1) || j == (yLength - 1)) {
- continue;
- }
- int rightRgb = templateImage.getRGB(i + 1, j);
- int downRgb = templateImage.getRGB(i, j + 1);
- //描边处理,,取带像素和无像素的界点,判断该点是不是临界轮廓点,如果是设置该坐标像素是白色
- if ((rgb >= 0 && rightRgb < 0) || (rgb < 0 && rightRgb >= 0) || (rgb >= 0 && downRgb < 0) || (rgb < 0 && downRgb >= 0)) {
- newImage.setRGB(i, j, Color.white.getRGB());
- oriImage.setRGB(x + i, y + j, Color.white.getRGB());
- }
- }
- }
-
- }
-
-
- /**
- * 干扰抠图处理
- *
- * @param oriImage 原图
- * @param templateImage 模板图
- * @param x 随机扣取坐标X
- * @param y 随机扣取坐标y
- * @throws Exception
- */
- private static void interferenceByTemplate(BufferedImage oriImage, BufferedImage templateImage, int x, int y) {
- //临时数组遍历用于高斯模糊存周边像素值
- int[][] martrix = new int[3][3];
- int[] values = new int[9];
-
- int xLength = templateImage.getWidth();
- int yLength = templateImage.getHeight();
- // 模板图像宽度
- for (int i = 0; i < xLength; i++) {
- // 模板图片高度
- for (int j = 0; j < yLength; j++) {
- // 如果模板图像当前像素点不是透明色 copy源文件信息到目标图片中
- int rgb = templateImage.getRGB(i, j);
- if (rgb < 0) {
- //抠图区域高斯模糊
- readPixel(oriImage, x + i, y + j, values);
- fillMatrix(martrix, values);
- oriImage.setRGB(x + i, y + j, avgMatrix(martrix));
- }
- //防止数组越界判断
- if (i == (xLength - 1) || j == (yLength - 1)) {
- continue;
- }
- int rightRgb = templateImage.getRGB(i + 1, j);
- int downRgb = templateImage.getRGB(i, j + 1);
- //描边处理,,取带像素和无像素的界点,判断该点是不是临界轮廓点,如果是设置该坐标像素是白色
- if ((rgb >= 0 && rightRgb < 0) || (rgb < 0 && rightRgb >= 0) || (rgb >= 0 && downRgb < 0) || (rgb < 0 && downRgb >= 0)) {
- oriImage.setRGB(x + i, y + j, Color.white.getRGB());
- }
- }
- }
-
- }
-
- private static void readPixel(BufferedImage img, int x, int y, int[] pixels) {
- int xStart = x - 1;
- int yStart = y - 1;
- int current = 0;
- for (int i = xStart; i < 3 + xStart; i++) {
- for (int j = yStart; j < 3 + yStart; j++) {
- int tx = i;
- if (tx < 0) {
- tx = -tx;
-
- } else if (tx >= img.getWidth()) {
- tx = x;
- }
- int ty = j;
- if (ty < 0) {
- ty = -ty;
- } else if (ty >= img.getHeight()) {
- ty = y;
- }
- pixels[current++] = img.getRGB(tx, ty);
-
- }
- }
- }
-
- private static void fillMatrix(int[][] matrix, int[] values) {
- int filled = 0;
- for (int i = 0; i < matrix.length; i++) {
- int[] x = matrix[i];
- for (int j = 0; j < x.length; j++) {
- x[j] = values[filled++];
- }
- }
- }
-
- private static int avgMatrix(int[][] matrix) {
- int r = 0;
- int g = 0;
- int b = 0;
- for (int i = 0; i < matrix.length; i++) {
- int[] x = matrix[i];
- for (int j = 0; j < x.length; j++) {
- if (j == 1) {
- continue;
- }
- Color c = new Color(x[j]);
- r += c.getRed();
- g += c.getGreen();
- b += c.getBlue();
- }
- }
- return new Color(r / 8, g / 8, b / 8).getRGB();
- }
-
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/CaptchaCacheServiceMemImpl.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/CaptchaCacheServiceMemImpl.java
deleted file mode 100644
index 7739b1a4b..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/CaptchaCacheServiceMemImpl.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.anji.captcha.service.impl;
-
-import com.anji.captcha.service.CaptchaCacheService;
-import com.anji.captcha.util.CacheUtil;
-
-import java.util.Objects;
-
-/**
- * 对于分布式部署的应用,我们建议应用自己实现CaptchaCacheService,比如用Redis,参考service/spring-boot代码示例。
- * 如果应用是单点的,也没有使用redis,那默认使用内存。
- * 内存缓存只适合单节点部署的应用,否则验证码生产与验证在节点之间信息不同步,导致失败。
- *
- * @author lide1202@hotmail.com
- * @Title: 默认使用内存当缓存
- * @date 2020-05-12
- */
-public class CaptchaCacheServiceMemImpl implements CaptchaCacheService {
- @Override
- public void set(String key, String value, long expiresInSeconds) {
-
- CacheUtil.set(key, value, expiresInSeconds);
- }
-
- @Override
- public boolean exists(String key) {
- return CacheUtil.exists(key);
- }
-
- @Override
- public void delete(String key) {
- CacheUtil.delete(key);
- }
-
- @Override
- public String get(String key) {
- return CacheUtil.get(key);
- }
-
- @Override
- public Long increment(String key, long val) {
- Long ret = Long.parseLong(Objects.requireNonNull(CacheUtil.get(key))) + val;
- CacheUtil.set(key, ret + "", 0);
- return ret;
- }
-
- @Override
- public String type() {
- return "local";
- }
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/CaptchaServiceFactory.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/CaptchaServiceFactory.java
deleted file mode 100644
index ceb91391a..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/CaptchaServiceFactory.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.anji.captcha.service.impl;
-
-import com.anji.captcha.model.common.Const;
-import com.anji.captcha.service.CaptchaCacheService;
-import com.anji.captcha.service.CaptchaService;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.ServiceLoader;
-
-/**
- * Created by raodeming on 2020/5/26.
- */
-@Slf4j
-public class CaptchaServiceFactory {
-
- public static CaptchaService getInstance(Properties config) {
- //先把所有CaptchaService初始化,通过init方法,实例字体等,add by lide1202@hotmail.com
- /*try{
- for(CaptchaService item: instances.values()){
- item.init(config);
- }
- }catch (Exception e){
- logger.warn("init captchaService fail:{}", e);
- }*/
-
- String captchaType = config.getProperty(Const.CAPTCHA_TYPE, "default");
- CaptchaService ret = instances.get(captchaType);
- if (ret == null) {
- throw new RuntimeException("unsupported-[captcha.type]=" + captchaType);
- }
- ret.init(config);
- return ret;
- }
-
- public static CaptchaCacheService getCache(String cacheType) {
- return cacheService.get(cacheType);
- }
-
- public volatile static Map instances = new HashMap<>();
- public volatile static Map cacheService = new HashMap<>();
-
- static {
- ServiceLoader cacheServices = ServiceLoader.load(CaptchaCacheService.class);
- for (CaptchaCacheService item : cacheServices) {
- cacheService.put(item.type(), item);
- }
- log.info("supported-captchaCache-service:{}", cacheService.keySet().toString());
- ServiceLoader services = ServiceLoader.load(CaptchaService.class);
- for (CaptchaService item : services) {
- instances.put(item.captchaType(), item);
- }
- ;
- log.info("supported-captchaTypes-service:{}", instances.keySet().toString());
- }
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/ClickWordCaptchaServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/ClickWordCaptchaServiceImpl.java
deleted file mode 100644
index 88b0fcbfd..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/ClickWordCaptchaServiceImpl.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- *Copyright © 2018 anji-plus
- *安吉加加信息技术有限公司
- *http://www.anji-plus.com
- *All rights reserved.
- */
-package com.anji.captcha.service.impl;
-
-import cn.hutool.core.util.StrUtil;
-import com.anji.captcha.model.common.CaptchaTypeEnum;
-import com.anji.captcha.model.common.Const;
-import com.anji.captcha.model.common.RepCodeEnum;
-import com.anji.captcha.model.common.ResponseModel;
-import com.anji.captcha.model.vo.CaptchaVO;
-import com.anji.captcha.model.vo.PointVO;
-import com.anji.captcha.service.impl.AbstractCaptchaService;
-import com.anji.captcha.service.impl.CaptchaServiceFactory;
-import com.anji.captcha.util.AESUtil;
-import com.anji.captcha.util.ImageUtils;
-import com.anji.captcha.util.JsonUtil;
-import com.anji.captcha.util.RandomUtils;
-import lombok.extern.slf4j.Slf4j;
-
-import java.awt.*;
-import java.awt.geom.AffineTransform;
-import java.awt.image.BufferedImage;
-import java.util.List;
-import java.util.*;
-
-/**
- * 点选文字验证码
- *
- * Created by raodeming on 2019/12/25.
- */
-@Slf4j
-public class ClickWordCaptchaServiceImpl extends AbstractCaptchaService {
-
- public static String HAN_ZI = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6";
-
- protected static String clickWordFontStr = "NotoSerif-Light.ttf";
-
- protected Font clickWordFont;//点选文字字体
-
- @Override
- public String captchaType() {
- return CaptchaTypeEnum.CLICKWORD.getCodeValue();
- }
-
- @Override
- public void init(Properties config) {
- super.init(config);
- clickWordFontStr = config.getProperty(Const.CAPTCHA_FONT_TYPE, "SourceHanSansCN-Normal.otf");
- try {
- int size = Integer.parseInt(config.getProperty(Const.CAPTCHA_FONT_SIZE,HAN_ZI_SIZE+""));
-
- if (clickWordFontStr.toLowerCase().endsWith(".ttf")
- || clickWordFontStr.toLowerCase().endsWith(".ttc")
- || clickWordFontStr.toLowerCase().endsWith(".otf")) {
- this.clickWordFont = Font.createFont(Font.TRUETYPE_FONT,
- Objects.requireNonNull(getClass().getResourceAsStream("/fonts/" + clickWordFontStr)))
- .deriveFont(Font.BOLD, size);
- } else {
- int style = Integer.parseInt(config.getProperty(Const.CAPTCHA_FONT_STYLE,Font.BOLD+""));
- this.clickWordFont = new Font(clickWordFontStr, style, size);
- }
- } catch (Exception ex) {
- log.error("load font error:{}", ex);
- }
- this.wordTotalCount = Integer.parseInt(config.getProperty(Const.CAPTCHA_WORD_COUNT,"4"));
- }
-
- @Override
- public void destroy(Properties config) {
- log.info("start-clear-history-data-", captchaType());
- }
-
- @Override
- public ResponseModel get(CaptchaVO captchaVO) {
- ResponseModel r = super.get(captchaVO);
- if (!validatedReq(r)) {
- return r;
- }
- BufferedImage bufferedImage = ImageUtils.getPicClick();
- if (null == bufferedImage) {
- log.error("滑动底图未初始化成功,请检查路径");
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_BASEMAP_NULL);
- }
- CaptchaVO imageData = getImageData(bufferedImage);
- if (imageData == null
- || StrUtil.isBlank(imageData.getOriginalImageBase64())) {
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_ERROR);
- }
- return ResponseModel.successData(imageData);
- }
-
- @Override
- public ResponseModel check(CaptchaVO captchaVO) {
- ResponseModel r = super.check(captchaVO);
- if (!validatedReq(r)) {
- return r;
- }
- //取坐标信息
- String codeKey = String.format(REDIS_CAPTCHA_KEY, captchaVO.getToken());
- if (!com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_INVALID);
- }
- String s = com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).get(codeKey);
- //验证码只用一次,即刻失效
- com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
- List point = null;
- List point1 = null;
- String pointJson = null;
- /**
- * [
- * {
- * "x": 85.0,
- * "y": 34.0
- * },
- * {
- * "x": 129.0,
- * "y": 56.0
- * },
- * {
- * "x": 233.0,
- * "y": 27.0
- * }
- * ]
- */
- try {
- point = JsonUtil.parseArray(s, PointVO.class);
- //aes解密
- pointJson = decrypt(captchaVO.getPointJson(), point.get(0).getSecretKey());
- point1 = JsonUtil.parseArray(pointJson, PointVO.class);
- } catch (Exception e) {
- log.error("验证码坐标解析失败", e);
- afterValidateFail(captchaVO);
- return ResponseModel.errorMsg(e.getMessage());
- }
- for (int i = 0; i < point.size(); i++) {
- if (point.get(i).x - HAN_ZI_SIZE > point1.get(i).x
- || point1.get(i).x > point.get(i).x + HAN_ZI_SIZE
- || point.get(i).y - HAN_ZI_SIZE > point1.get(i).y
- || point1.get(i).y > point.get(i).y + HAN_ZI_SIZE) {
- afterValidateFail(captchaVO);
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_COORDINATE_ERROR);
- }
- }
- //校验成功,将信息存入缓存
- String secretKey = point.get(0).getSecretKey();
- String value = null;
- try {
- value = AESUtil.aesEncrypt(captchaVO.getToken().concat("---").concat(pointJson), secretKey);
- } catch (Exception e) {
- log.error("AES加密失败", e);
- afterValidateFail(captchaVO);
- return ResponseModel.errorMsg(e.getMessage());
- }
- String secondKey = String.format(REDIS_SECOND_CAPTCHA_KEY, value);
- com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).set(secondKey, captchaVO.getToken(), EXPIRESIN_THREE);
- captchaVO.setResult(true);
- captchaVO.resetClientFlag();
- return ResponseModel.successData(captchaVO);
- }
-
- @Override
- public ResponseModel verification(CaptchaVO captchaVO) {
- /*if (captchaVO == null) {
- return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
- }
- if (StrUtil.isEmpty(captchaVO.getCaptchaVerification())) {
- return RepCodeEnum.NULL_ERROR.parseError("captchaVerification");
- }*/
- ResponseModel r = super.verification(captchaVO);
- if (!validatedReq(r)) {
- return r;
- }
- try {
- String codeKey = String.format(REDIS_SECOND_CAPTCHA_KEY, captchaVO.getCaptchaVerification());
- if (!com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_INVALID);
- }
- //二次校验取值后,即刻失效
- com.anji.captcha.service.impl.CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
- } catch (Exception e) {
- log.error("验证码坐标解析失败", e);
- return ResponseModel.errorMsg(e.getMessage());
- }
- return ResponseModel.success();
- }
-
- public int getWordTotalCount() {
- return wordTotalCount;
- }
-
- public void setWordTotalCount(int wordTotalCount) {
- this.wordTotalCount = wordTotalCount;
- }
-
- public boolean isFontColorRandom() {
- return fontColorRandom;
- }
-
- public void setFontColorRandom(boolean fontColorRandom) {
- this.fontColorRandom = fontColorRandom;
- }
-
- /**
- * 点选文字 字体总个数
- */
- private int wordTotalCount = 4;
- /**
- * 点选文字 字体颜色是否随机
- */
- private boolean fontColorRandom = Boolean.TRUE;
-
- private CaptchaVO getImageData(BufferedImage backgroundImage) {
- CaptchaVO dataVO = new CaptchaVO();
- List wordList = new ArrayList();
- List pointList = new ArrayList();
-
- Graphics backgroundGraphics = backgroundImage.getGraphics();
- int width = backgroundImage.getWidth();
- int height = backgroundImage.getHeight();
-
- int wordCount = getWordTotalCount();
- //定义随机1到arr.length某一个字不参与校验
- int num = RandomUtils.getRandomInt(1, wordCount);
- Set currentWords = getRandomWords(wordCount);
- String secretKey = null;
- if (captchaAesStatus) {
- secretKey = AESUtil.getKey();
- }
- /*for (int i = 0; i < wordCount; i++) {
- String word;
- do {
- word = RandomUtils.getRandomHan(HAN_ZI);
- currentWords.add(word);
- } while (!currentWords.contains(word));*/
- int i = 0;
- for (String word : currentWords) {
- //随机字体坐标
- PointVO point = randomWordPoint(width, height, i, wordCount);
- point.setSecretKey(secretKey);
- //随机字体颜色
- if (isFontColorRandom()) {
- backgroundGraphics.setColor(new Color(RandomUtils.getRandomInt(1, 255),
- RandomUtils.getRandomInt(1, 255), RandomUtils.getRandomInt(1, 255)));
- } else {
- backgroundGraphics.setColor(Color.BLACK);
- }
- //设置角度
- AffineTransform affineTransform = new AffineTransform();
- affineTransform.rotate(Math.toRadians(RandomUtils.getRandomInt(-45, 45)), 0, 0);
- Font rotatedFont = clickWordFont.deriveFont(affineTransform);
- backgroundGraphics.setFont(rotatedFont);
- backgroundGraphics.drawString(word, point.getX(), point.getY());
-
- if ((num - 1) != i) {
- wordList.add(word);
- pointList.add(point);
- }
- i++;
- }
-
- backgroundGraphics.setFont(waterMarkFont);
- backgroundGraphics.setColor(Color.white);
- backgroundGraphics.drawString(waterMark, width - getEnOrChLength(waterMark), height - (HAN_ZI_SIZE / 2) + 7);
-
- //创建合并图片
- BufferedImage combinedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- Graphics combinedGraphics = combinedImage.getGraphics();
- combinedGraphics.drawImage(backgroundImage, 0, 0, null);
-
- dataVO.setOriginalImageBase64(ImageUtils.getImageToBase64Str(backgroundImage).replaceAll("\r|\n", ""));
- //pointList信息不传到前端,只做后端check校验
- //dataVO.setPointList(pointList);
- dataVO.setWordList(wordList);
- dataVO.setToken(RandomUtils.getUUID());
- dataVO.setSecretKey(secretKey);
- //将坐标信息存入redis中
- String codeKey = String.format(REDIS_CAPTCHA_KEY, dataVO.getToken());
- CaptchaServiceFactory.getCache(cacheType).set(codeKey, JsonUtil.toJSONString(pointList), EXPIRESIN_SECONDS);
-// base64StrToImage(getImageToBase64Str(backgroundImage), "D:\\点击.png");
- return dataVO;
- }
-
- private Set getRandomWords(int wordCount) {
- Set words = new HashSet<>();
- int size = HAN_ZI.length();
- for (; ; ) {
- String t = HAN_ZI.charAt(RandomUtils.getRandomInt(size)) + "";
- words.add(t);
- if (words.size() >= wordCount) {
- break;
- }
- }
- return words;
- }
-
- /**
- * 随机字体循环排序下标
- *
- * @param imageWidth 图片宽度
- * @param imageHeight 图片高度
- * @param wordSortIndex 字体循环排序下标(i)
- * @param wordCount 字数量
- * @return
- */
- private static PointVO randomWordPoint(int imageWidth, int imageHeight, int wordSortIndex, int wordCount) {
- int avgWidth = imageWidth / (wordCount + 1);
- int x, y;
- if (avgWidth < HAN_ZI_SIZE_HALF) {
- x = RandomUtils.getRandomInt(1 + HAN_ZI_SIZE_HALF, imageWidth);
- } else {
- if (wordSortIndex == 0) {
- x = RandomUtils.getRandomInt(1 + HAN_ZI_SIZE_HALF, avgWidth * (wordSortIndex + 1) - HAN_ZI_SIZE_HALF);
- } else {
- x = RandomUtils.getRandomInt(avgWidth * wordSortIndex + HAN_ZI_SIZE_HALF, avgWidth * (wordSortIndex + 1) - HAN_ZI_SIZE_HALF);
- }
- }
- y = RandomUtils.getRandomInt(HAN_ZI_SIZE, imageHeight - HAN_ZI_SIZE);
- return new PointVO(x, y, null);
- }
-
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/DefaultCaptchaServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/DefaultCaptchaServiceImpl.java
deleted file mode 100644
index 9f75fa8af..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/DefaultCaptchaServiceImpl.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- *Copyright © 2018 anji-plus
- *安吉加加信息技术有限公司
- *http://www.anji-plus.com
- *All rights reserved.
- */
-package com.anji.captcha.service.impl;
-
-import cn.hutool.core.util.StrUtil;
-import com.anji.captcha.model.common.RepCodeEnum;
-import com.anji.captcha.model.common.ResponseModel;
-import com.anji.captcha.model.vo.CaptchaVO;
-import com.anji.captcha.service.CaptchaService;
-import com.anji.captcha.service.impl.AbstractCaptchaService;
-import com.anji.captcha.service.impl.CaptchaServiceFactory;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.Properties;
-
-/**
- * Created by raodeming on 2019/12/25.
- */
-@Slf4j
-public class DefaultCaptchaServiceImpl extends AbstractCaptchaService {
-
- @Override
- public String captchaType() {
- return "default";
- }
-
- @Override
- public void init(Properties config) {
- for (String s : CaptchaServiceFactory.instances.keySet()) {
- if(captchaType().equals(s)){
- continue;
- }
- getService(s).init(config);
- }
- }
-
- @Override
- public void destroy(Properties config) {
- for (String s : CaptchaServiceFactory.instances.keySet()) {
- if(captchaType().equals(s)){
- continue;
- }
- getService(s).destroy(config);
- }
- }
-
- private CaptchaService getService(String captchaType){
- return CaptchaServiceFactory.instances.get(captchaType);
- }
-
- @Override
- public ResponseModel get(CaptchaVO captchaVO) {
- if (captchaVO == null) {
- return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
- }
- if (StrUtil.isEmpty(captchaVO.getCaptchaType())) {
- return RepCodeEnum.NULL_ERROR.parseError("类型");
- }
- return getService(captchaVO.getCaptchaType()).get(captchaVO);
- }
-
- @Override
- public ResponseModel check(CaptchaVO captchaVO) {
- if (captchaVO == null) {
- return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
- }
- if (StrUtil.isEmpty(captchaVO.getCaptchaType())) {
- return RepCodeEnum.NULL_ERROR.parseError("类型");
- }
- if (StrUtil.isEmpty(captchaVO.getToken())) {
- return RepCodeEnum.NULL_ERROR.parseError("token");
- }
- return getService(captchaVO.getCaptchaType()).check(captchaVO);
- }
-
- @Override
- public ResponseModel verification(CaptchaVO captchaVO) {
- if (captchaVO == null) {
- return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
- }
- if (StrUtil.isEmpty(captchaVO.getCaptchaVerification())) {
- return RepCodeEnum.NULL_ERROR.parseError("二次校验参数");
- }
- try {
- String codeKey = String.format(REDIS_SECOND_CAPTCHA_KEY, captchaVO.getCaptchaVerification());
- if (!CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {
- return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_INVALID);
- }
- //二次校验取值后,即刻失效
- CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
- } catch (Exception e) {
- log.error("验证码坐标解析失败", e);
- return ResponseModel.errorMsg(e.getMessage());
- }
- return ResponseModel.success();
- }
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/FrequencyLimitHandler.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/FrequencyLimitHandler.java
deleted file mode 100644
index a477db2f9..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/service/impl/FrequencyLimitHandler.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.anji.captcha.service.impl;
-
-import cn.hutool.core.util.StrUtil;
-import com.anji.captcha.model.common.Const;
-import com.anji.captcha.model.common.RepCodeEnum;
-import com.anji.captcha.model.common.ResponseModel;
-import com.anji.captcha.model.vo.CaptchaVO;
-import com.anji.captcha.service.CaptchaCacheService;
-
-import java.util.Objects;
-import java.util.Properties;
-
-/**
- * @author WongBin
- * @date 2021/1/21
- */
-public interface FrequencyLimitHandler {
-
- String LIMIT_KEY = "AJ.CAPTCHA.REQ.LIMIT-%s-%s";
-
- /**
- * get 接口限流
- *
- * @param captchaVO
- * @return
- */
- ResponseModel validateGet(CaptchaVO captchaVO);
-
- /**
- * check接口限流
- *
- * @param captchaVO
- * @return
- */
- ResponseModel validateCheck(CaptchaVO captchaVO);
-
- /**
- * verify接口限流
- *
- * @param captchaVO
- * @return
- */
- ResponseModel validateVerify(CaptchaVO captchaVO);
-
-
- /***
- * 验证码接口限流:
- * 客户端ClientUid 组件实例化时设置一次,如:场景码+UUID,客户端可以本地缓存,保证一个组件只有一个值
- *
- * 针对同一个客户端的请求,做如下限制:
- * get
- * 1分钟内check失败5次,锁定5分钟
- * 1分钟内不能超过120次。
- * check:
- * 1分钟内不超过600次
- * verify:
- * 1分钟内不超过600次
- */
- class DefaultLimitHandler implements FrequencyLimitHandler {
- private Properties config;
- private CaptchaCacheService cacheService;
-
- public DefaultLimitHandler(Properties config, CaptchaCacheService cacheService) {
- this.config = config;
- this.cacheService = cacheService;
- }
-
- private String getClientCId(CaptchaVO input, String type) {
- return String.format(LIMIT_KEY, type, input.getClientUid());
- }
-
- @Override
- public ResponseModel validateGet(CaptchaVO d) {
- // 无客户端身份标识,不限制
- if (StrUtil.isEmpty(d.getClientUid())) {
- return null;
- }
- String getKey = getClientCId(d, "GET");
- String lockKey = getClientCId(d, "LOCK");
- // 失败次数过多,锁定
- if (Objects.nonNull(cacheService.get(lockKey))) {
- return ResponseModel.errorMsg(RepCodeEnum.API_REQ_LOCK_GET_ERROR);
- }
- String getCnts = cacheService.get(getKey);
- if (Objects.isNull(getCnts)) {
- cacheService.set(getKey, "1", 60);
- getCnts = "1";
- }
- cacheService.increment(getKey, 1);
- // 1分钟内请求次数过多
- if (Long.parseLong(getCnts) > Long.parseLong(config.getProperty(Const.REQ_GET_MINUTE_LIMIT, "120"))) {
- return ResponseModel.errorMsg(RepCodeEnum.API_REQ_LIMIT_GET_ERROR);
- }
-
- // 失败次数验证
- String failKey = getClientCId(d, "FAIL");
- String failCnts = cacheService.get(failKey);
- // 没有验证失败,通过校验
- if (Objects.isNull(failCnts)) {
- return null;
- }
- // 1分钟内失败5次
- if (Long.parseLong(failCnts) > Long.parseLong(config.getProperty(Const.REQ_GET_LOCK_LIMIT, "5"))) {
- // get接口锁定5分钟
- cacheService.set(lockKey, "1", Long.parseLong(config.getProperty(Const.REQ_GET_LOCK_SECONDS, "300")));
- return ResponseModel.errorMsg(RepCodeEnum.API_REQ_LOCK_GET_ERROR);
- }
- return null;
- }
-
- @Override
- public ResponseModel validateCheck(CaptchaVO d) {
- // 无客户端身份标识,不限制
- if (StrUtil.isEmpty(d.getClientUid())) {
- return null;
- }
- /*String getKey = getClientCId(d, "GET");
- if(Objects.isNull(cacheService.get(getKey))){
- return ResponseModel.errorMsg(RepCodeEnum.API_REQ_INVALID);
- }*/
- String key = getClientCId(d, "CHECK");
- String v = cacheService.get(key);
- if (Objects.isNull(v)) {
- cacheService.set(key, "1", 60);
- v = "1";
- }
- cacheService.increment(key, 1);
- if (Long.parseLong(v) > Long.parseLong(config.getProperty(Const.REQ_CHECK_MINUTE_LIMIT, "600"))) {
- return ResponseModel.errorMsg(RepCodeEnum.API_REQ_LIMIT_CHECK_ERROR);
- }
- return null;
- }
-
- @Override
- public ResponseModel validateVerify(CaptchaVO d) {
- /*String getKey = getClientCId(d, "GET");
- if(Objects.isNull(cacheService.get(getKey))){
- return ResponseModel.errorMsg(RepCodeEnum.API_REQ_INVALID);
- }*/
- String key = getClientCId(d, "VERIFY");
- String v = cacheService.get(key);
- if (Objects.isNull(v)) {
- cacheService.set(key, "1", 60);
- v = "1";
- }
- cacheService.increment(key, 1);
- if (Long.parseLong(v) > Long.parseLong(config.getProperty(Const.REQ_VALIDATE_MINUTE_LIMIT, "600"))) {
- return ResponseModel.errorMsg(RepCodeEnum.API_REQ_LIMIT_VERIFY_ERROR);
- }
- return null;
- }
- }
-
-}
\ No newline at end of file
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/AESUtil.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/AESUtil.java
deleted file mode 100644
index 9eaf84f53..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/AESUtil.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- *Copyright © 2018 anji-plus
- *安吉加加信息技术有限公司
- *http://www.anji-plus.com
- *All rights reserved.
- */
-package com.anji.captcha.util;
-
-
-import cn.hutool.core.util.StrUtil;
-import com.anji.captcha.util.RandomUtils;
-
-import javax.crypto.Cipher;
-import javax.crypto.KeyGenerator;
-import javax.crypto.spec.SecretKeySpec;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-
-
-public class AESUtil {
- //算法
- private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";
-
- /**
- * 获取随机key
- *
- * @return
- */
- public static String getKey() {
- return RandomUtils.getRandomString(16);
- }
-
-
- /**
- * 将byte[]转为各种进制的字符串
- *
- * @param bytes byte[]
- * @param radix 可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制
- * @return 转换后的字符串
- */
- public static String binary(byte[] bytes, int radix) {
- return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
- }
-
- /**
- * base 64 encode
- *
- * @param bytes 待编码的byte[]
- * @return 编码后的base 64 code
- */
- public static String base64Encode(byte[] bytes) {
- //return Base64.encodeBase64String(bytes);
- return Base64.getEncoder().encodeToString(bytes);
- }
-
- /**
- * base 64 decode
- *
- * @param base64Code 待解码的base 64 code
- * @return 解码后的byte[]
- * @throws Exception
- */
- public static byte[] base64Decode(String base64Code) throws Exception {
- Base64.Decoder decoder = Base64.getDecoder();
- return StrUtil.isEmpty(base64Code) ? null : decoder.decode(base64Code);
- }
-
-
- /**
- * AES加密
- *
- * @param content 待加密的内容
- * @param encryptKey 加密密钥
- * @return 加密后的byte[]
- * @throws Exception
- */
- public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
- KeyGenerator kgen = KeyGenerator.getInstance("AES");
- kgen.init(128);
- Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
- cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(encryptKey.getBytes(), "AES"));
-
- return cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
- }
-
-
- /**
- * AES加密为base 64 code
- *
- * @param content 待加密的内容
- * @param encryptKey 加密密钥
- * @return 加密后的base 64 code
- * @throws Exception
- */
- public static String aesEncrypt(String content, String encryptKey) throws Exception {
- if (StrUtil.isBlank(encryptKey)) {
- return content;
- }
- return base64Encode(aesEncryptToBytes(content, encryptKey));
- }
-
- /**
- * AES解密
- *
- * @param encryptBytes 待解密的byte[]
- * @param decryptKey 解密密钥
- * @return 解密后的String
- * @throws Exception
- */
- public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
- KeyGenerator kgen = KeyGenerator.getInstance("AES");
- kgen.init(128);
-
- Cipher cipher = Cipher.getInstance(ALGORITHMSTR);
- cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(decryptKey.getBytes(), "AES"));
- byte[] decryptBytes = cipher.doFinal(encryptBytes);
- return new String(decryptBytes);
- }
-
-
- /**
- * 将base 64 code AES解密
- *
- * @param encryptStr 待解密的base 64 code
- * @param decryptKey 解密密钥
- * @return 解密后的string
- * @throws Exception
- */
- public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
- if (StrUtil.isBlank(decryptKey)) {
- return encryptStr;
- }
- return StrUtil.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
- }
-
- /**
- * 测试
- */
- public static void main(String[] args) throws Exception {
- String randomString = RandomUtils.getRandomString(16);
- String content = "hahhahaahhahni";
- System.out.println("加密前:" + content);
- System.out.println("加密密钥和解密密钥:" + randomString);
- String encrypt = aesEncrypt(content, randomString);
- System.out.println("加密后:" + encrypt);
- String decrypt = aesDecrypt(encrypt, randomString);
- System.out.println("解密后:" + decrypt);
- }
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/CacheUtil.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/CacheUtil.java
deleted file mode 100644
index 617993526..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/CacheUtil.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- *Copyright © 2018 anji-plus
- *安吉加加信息技术有限公司
- *http://www.anji-plus.com
- *All rights reserved.
- */
-package com.anji.captcha.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Map;
-import java.util.concurrent.*;
-
-public final class CacheUtil {
- private static final Logger logger = LoggerFactory.getLogger(CacheUtil.class);
-
- private static final Map CACHE_MAP = new ConcurrentHashMap();
-
- /**
- * 缓存最大个数
- */
- private static Integer CACHE_MAX_NUMBER = 1000;
-
- /**
- * 初始化
- *
- * @param cacheMaxNumber 缓存最大个数
- * @param second 定时任务 秒执行清除过期缓存
- */
- public static void init(int cacheMaxNumber, long second) {
- CACHE_MAX_NUMBER = cacheMaxNumber;
- if (second > 0L) {
- /*Timer timer = new Timer();
- timer.schedule(new TimerTask() {
- @Override
- public void run() {
- refresh();
- }
- }, 0, second * 1000);*/
- ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
- @Override
- public Thread newThread(Runnable r) {
- return new Thread(r, "thd-captcha-cache-clean");
- }
- }, new ThreadPoolExecutor.CallerRunsPolicy());
- scheduledExecutor.scheduleAtFixedRate(new Runnable() {
- @Override
- public void run() {
- refresh();
- }
- }, 10, second, TimeUnit.SECONDS);
- }
- }
-
- /**
- * 缓存刷新,清除过期数据
- */
- public static void refresh() {
- logger.debug("local缓存刷新,清除过期数据");
- for (String key : CACHE_MAP.keySet()) {
- exists(key);
- }
- }
-
-
- public static void set(String key, String value, long expiresInSeconds) {
- //设置阈值,达到即clear缓存
- if (CACHE_MAP.size() > CACHE_MAX_NUMBER * 2) {
- logger.info("CACHE_MAP达到阈值,clear map");
- clear();
- }
- CACHE_MAP.put(key, value);
- if (expiresInSeconds > 0) {
- CACHE_MAP.put(key + "_HoldTime", System.currentTimeMillis() + expiresInSeconds * 1000);//缓存失效时间
- }
- }
-
- public static void delete(String key) {
- CACHE_MAP.remove(key);
- CACHE_MAP.remove(key + "_HoldTime");
- }
-
- public static boolean exists(String key) {
- Long cacheHoldTime = (Long) CACHE_MAP.get(key + "_HoldTime");
- if (cacheHoldTime == null || cacheHoldTime == 0L) {
- return false;
- }
- if (cacheHoldTime < System.currentTimeMillis()) {
- delete(key);
- return false;
- }
- return true;
- }
-
-
- public static String get(String key) {
- if (exists(key)) {
- return (String) CACHE_MAP.get(key);
- }
- return null;
- }
-
- /**
- * 删除所有缓存
- */
- public static void clear() {
- logger.debug("have clean all key !");
- CACHE_MAP.clear();
- }
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/FileCopyUtils.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/FileCopyUtils.java
deleted file mode 100644
index 83cb6fa6d..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/FileCopyUtils.java
+++ /dev/null
@@ -1,122 +0,0 @@
-package com.anji.captcha.util;
-//
-// Source code recreated from a .class file by IntelliJ IDEA
-// (powered by Fernflower decompiler)
-//
-
-import com.anji.captcha.util.StreamUtils;
-
-import java.io.*;
-import java.nio.file.Files;
-
-public abstract class FileCopyUtils {
- public static final int BUFFER_SIZE = 4096;
-
- public FileCopyUtils() {
- }
-
- public static int copy(File in, File out) throws IOException {
- return copy(Files.newInputStream(in.toPath()), Files.newOutputStream(out.toPath()));
- }
-
- public static void copy(byte[] in, File out) throws IOException {
- copy((InputStream) (new ByteArrayInputStream(in)), (OutputStream) Files.newOutputStream(out.toPath()));
- }
-
- public static byte[] copyToByteArray(File in) throws IOException {
- return copyToByteArray(Files.newInputStream(in.toPath()));
- }
-
- public static int copy(InputStream in, OutputStream out) throws IOException {
- int var2;
- try {
- var2 = StreamUtils.copy(in, out);
- } finally {
- try {
- in.close();
- } catch (IOException var12) {
- }
-
- try {
- out.close();
- } catch (IOException var11) {
- }
-
- }
-
- return var2;
- }
-
- public static void copy(byte[] in, OutputStream out) throws IOException {
- try {
- out.write(in);
- } finally {
- try {
- out.close();
- } catch (IOException var8) {
- }
-
- }
-
- }
-
- public static byte[] copyToByteArray(InputStream in) throws IOException {
- if (in == null) {
- return new byte[0];
- } else {
- ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
- copy((InputStream) in, (OutputStream) out);
- return out.toByteArray();
- }
- }
-
- public static int copy(Reader in, Writer out) throws IOException {
- try {
- int byteCount = 0;
- char[] buffer = new char[4096];
-
- int bytesRead;
- for (boolean var4 = true; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
- out.write(buffer, 0, bytesRead);
- }
-
- out.flush();
- return byteCount;
- } finally {
- try {
- in.close();
- } catch (IOException var15) {
- }
-
- try {
- out.close();
- } catch (IOException var14) {
- }
-
- }
- }
-
- public static void copy(String in, Writer out) throws IOException {
- try {
- out.write(in);
- } finally {
- try {
- out.close();
- } catch (IOException var8) {
- }
-
- }
-
- }
-
- public static String copyToString(Reader in) throws IOException {
- if (in == null) {
- return "";
- } else {
- StringWriter out = new StringWriter();
- copy((Reader) in, (Writer) out);
- return out.toString();
- }
- }
-}
-
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/ImageUtils.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/ImageUtils.java
deleted file mode 100644
index 1d6f0d4f8..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/ImageUtils.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- *Copyright © 2018 anji-plus
- *安吉加加信息技术有限公司
- *http://www.anji-plus.com
- *All rights reserved.
- */
-package com.anji.captcha.util;
-
-import cn.hutool.core.util.StrUtil;
-import com.anji.captcha.model.common.CaptchaBaseMapEnum;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.util.Base64Utils;
-
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
-import java.io.*;
-import java.util.Arrays;
-import java.util.Base64;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-@Slf4j
-public class ImageUtils {
- private static Map originalCacheMap = new ConcurrentHashMap(); //滑块底图
- private static Map slidingBlockCacheMap = new ConcurrentHashMap(); //滑块
- private static Map picClickCacheMap = new ConcurrentHashMap(); //点选文字
- private static Map fileNameMap = new ConcurrentHashMap<>();
-
- public static void cacheImage(String captchaOriginalPathJigsaw, String captchaOriginalPathClick) {
- //滑动拼图
- if (StrUtil.isBlank(captchaOriginalPathJigsaw)) {
- originalCacheMap.putAll(getResourcesImagesFile("defaultImages/jigsaw/original"));
- slidingBlockCacheMap.putAll(getResourcesImagesFile("defaultImages/jigsaw/slidingBlock"));
- } else {
- originalCacheMap.putAll(getImagesFile(captchaOriginalPathJigsaw + File.separator + "original"));
- slidingBlockCacheMap.putAll(getImagesFile(captchaOriginalPathJigsaw + File.separator + "slidingBlock"));
- }
- //点选文字
- if (StrUtil.isBlank(captchaOriginalPathClick)) {
- picClickCacheMap.putAll(getResourcesImagesFile("defaultImages/pic-click"));
- } else {
- picClickCacheMap.putAll(getImagesFile(captchaOriginalPathClick));
- }
- fileNameMap.put(CaptchaBaseMapEnum.ORIGINAL.getCodeValue(), originalCacheMap.keySet().toArray(new String[0]));
- fileNameMap.put(CaptchaBaseMapEnum.SLIDING_BLOCK.getCodeValue(), slidingBlockCacheMap.keySet().toArray(new String[0]));
- fileNameMap.put(CaptchaBaseMapEnum.PIC_CLICK.getCodeValue(), picClickCacheMap.keySet().toArray(new String[0]));
- log.info("初始化底图:{}", JsonUtil.toJSONString(fileNameMap));
- }
-
- public static void cacheBootImage(Map originalMap, Map slidingBlockMap, Map picClickMap) {
- originalCacheMap.putAll(originalMap);
- slidingBlockCacheMap.putAll(slidingBlockMap);
- picClickCacheMap.putAll(picClickMap);
- fileNameMap.put(CaptchaBaseMapEnum.ORIGINAL.getCodeValue(), originalCacheMap.keySet().toArray(new String[0]));
- fileNameMap.put(CaptchaBaseMapEnum.SLIDING_BLOCK.getCodeValue(), slidingBlockCacheMap.keySet().toArray(new String[0]));
- fileNameMap.put(CaptchaBaseMapEnum.PIC_CLICK.getCodeValue(), picClickCacheMap.keySet().toArray(new String[0]));
- log.info("自定义resource底图:{}", JsonUtil.toJSONString(fileNameMap));
- }
-
-
- public static BufferedImage getOriginal() {
- String[] strings = fileNameMap.get(CaptchaBaseMapEnum.ORIGINAL.getCodeValue());
- if (null == strings || strings.length == 0) {
- return null;
- }
- Integer randomInt = com.anji.captcha.util.RandomUtils.getRandomInt(0, strings.length);
- String s = originalCacheMap.get(strings[randomInt]);
- return getBase64StrToImage(s);
- }
-
- public static String getslidingBlock() {
- String[] strings = fileNameMap.get(CaptchaBaseMapEnum.SLIDING_BLOCK.getCodeValue());
- if (null == strings || strings.length == 0) {
- return null;
- }
- Integer randomInt = com.anji.captcha.util.RandomUtils.getRandomInt(0, strings.length);
- return slidingBlockCacheMap.get(strings[randomInt]);
- }
-
- public static BufferedImage getPicClick() {
- String[] strings = fileNameMap.get(CaptchaBaseMapEnum.PIC_CLICK.getCodeValue());
- if (null == strings || strings.length == 0) {
- return null;
- }
- Integer randomInt = RandomUtils.getRandomInt(0, strings.length);
- String s = picClickCacheMap.get(strings[randomInt]);
- return getBase64StrToImage(s);
- }
-
- /**
- * 图片转base64 字符串
- *
- * @param templateImage
- * @return
- */
- public static String getImageToBase64Str(BufferedImage templateImage) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- ImageIO.write(templateImage, "png", baos);
- } catch (IOException e) {
- e.printStackTrace();
- }
- byte[] bytes = baos.toByteArray();
-
- Base64.Encoder encoder = Base64.getEncoder();
-
- return encoder.encodeToString(bytes).trim();
- }
-
- /**
- * base64 字符串转图片
- *
- * @param base64String
- * @return
- */
- public static BufferedImage getBase64StrToImage(String base64String) {
- try {
- Base64.Decoder decoder = Base64.getDecoder();
- byte[] bytes = decoder.decode(base64String);
- ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
- return ImageIO.read(inputStream);
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
-
-
- private static Map getResourcesImagesFile(String path) {
- //默认提供六张底图
- Map imgMap = new HashMap<>();
- ClassLoader classLoader = ImageUtils.class.getClassLoader();
- for (int i = 1; i <= 6; i++) {
- InputStream resourceAsStream = classLoader.getResourceAsStream(path.concat("/").concat(String.valueOf(i).concat(".png")));
- byte[] bytes = new byte[0];
- try {
- bytes = FileCopyUtils.copyToByteArray(resourceAsStream);
- } catch (IOException e) {
- e.printStackTrace();
- }
- String string = Base64Utils.encodeToString(bytes);
- String filename = String.valueOf(i).concat(".png");
- imgMap.put(filename, string);
- }
- return imgMap;
- }
-
- private static Map getImagesFile(String path) {
- Map imgMap = new HashMap<>();
- File file = new File(path);
- if (!file.exists()) {
- return new HashMap<>();
- }
- File[] files = file.listFiles();
- Arrays.stream(files).forEach(item -> {
- try {
- FileInputStream fileInputStream = new FileInputStream(item);
- byte[] bytes = FileCopyUtils.copyToByteArray(fileInputStream);
- String string = Base64Utils.encodeToString(bytes);
- imgMap.put(item.getName(), string);
- } catch (IOException e) {
- e.printStackTrace();
- }
- });
- return imgMap;
- }
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/JsonUtil.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/JsonUtil.java
deleted file mode 100644
index ee2e34894..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/JsonUtil.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.anji.captcha.util;
-
-import com.anji.captcha.model.vo.PointVO;
-import lombok.extern.slf4j.Slf4j;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * 替换掉fastjson,自定义实现相关方法
- * note: 该实现不具有通用性,仅用于本项目。
- *
- * @author WongBin
- * @date 2021/1/8
- */
-@Slf4j
-public class JsonUtil {
- public static List parseArray(String text, Class clazz) {
- if (text == null) {
- return null;
- } else {
- String[] arr = text.replaceFirst("\\[", "")
- .replaceFirst("\\]", "").split("\\}");
- List ret = new ArrayList<>(arr.length);
- for (String s : arr) {
- ret.add(parseObject(s, PointVO.class));
- }
- return ret;
- }
- }
-
- public static PointVO parseObject(String text, Class clazz) {
- if (text == null) {
- return null;
- }
- /*if(!clazz.isAssignableFrom(PointVO.class)) {
- throw new UnsupportedOperationException("不支持的输入类型:"
- + clazz.getSimpleName());
- }*/
- try {
- PointVO ret = clazz.newInstance();
- return ret.parse(text);
- } catch (Exception ex) {
- log.error("json解析异常", ex);
-
- }
- return null;
- }
-
- public static String toJSONString(Object object) {
- if (object == null) {
- return "{}";
- }
- if (object instanceof PointVO) {
- PointVO t = (PointVO) object;
- return t.toJsonString();
- }
- if (object instanceof List) {
- List list = (List) object;
- StringBuilder buf = new StringBuilder("[");
- list.forEach(t -> {
- buf.append(t.toJsonString()).append(",");
- });
- return buf.deleteCharAt(buf.lastIndexOf(",")).append("]").toString();
- }
- if (object instanceof Map) {
- return ((Map) object).entrySet().toString();
- }
- throw new UnsupportedOperationException("不支持的输入类型:"
- + object.getClass().getSimpleName());
- }
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/MD5Util.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/MD5Util.java
deleted file mode 100644
index 3bb2f6ef6..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/MD5Util.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.anji.captcha.util;
-
-import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-
-/**
- * @Title: MD5工具类
- */
-public abstract class MD5Util {
- /**
- * 获取指定字符串的md5值
- *
- * @param dataStr 明文
- * @return String
- */
- public static String md5(String dataStr) {
- try {
- MessageDigest m = MessageDigest.getInstance("MD5");
- m.update(dataStr.getBytes(StandardCharsets.UTF_8));
- byte[] s = m.digest();
- StringBuilder result = new StringBuilder();
- for (byte b : s) {
- result.append(Integer.toHexString((0x000000FF & b) | 0xFFFFFF00).substring(6));
- }
- return result.toString();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return "";
- }
-
- /**
- * 获取指定字符串的md5值, md5(str+salt)
- *
- * @param dataStr 明文
- * @return String
- */
- public static String md5WithSalt(String dataStr, String salt) {
- return md5(dataStr + salt);
- }
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/RandomUtils.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/RandomUtils.java
deleted file mode 100644
index 819cf2f30..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/RandomUtils.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- *Copyright © 2018 anji-plus
- *安吉加加信息技术有限公司
- *http://www.anji-plus.com
- *All rights reserved.
- */
-package com.anji.captcha.util;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Random;
-import java.util.UUID;
-import java.util.concurrent.ThreadLocalRandom;
-
-
-public class RandomUtils {
-
- /**
- * 生成UUID
- *
- * @return
- */
- public static String getUUID() {
- String uuid = UUID.randomUUID().toString();
- uuid = uuid.replace("-", "");
- return uuid;
- }
-
- /**
- * 获取指定文字的随机中文
- *
- * @return
- */
- public static String getRandomHan(String hanZi) {
- return hanZi.charAt(new Random().nextInt(hanZi.length())) + "";
- }
-
- public static int getRandomInt(int bound) {
- return ThreadLocalRandom.current().nextInt(bound);
- }
-
- /**
- * 获取随机中文
- *
- * @return
- */
- public static String getRandomHan() {
- String str = "";
- int highCode;
- int lowCode;
-
- Random random = new Random();
-
- highCode = (176 + Math.abs(random.nextInt(39))); //B0 + 0~39(16~55) 一级汉字所占区
- lowCode = (161 + Math.abs(random.nextInt(93))); //A1 + 0~93 每区有94个汉字
-
- byte[] b = new byte[2];
- b[0] = (Integer.valueOf(highCode)).byteValue();
- b[1] = (Integer.valueOf(lowCode)).byteValue();
-
- try {
- str = new String(b, "GBK");
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- return str;
- }
-
- /**
- * 随机范围内数字
- *
- * @param startNum
- * @param endNum
- * @return
- */
- public static Integer getRandomInt(int startNum, int endNum) {
- return ThreadLocalRandom.current().nextInt(endNum - startNum) + startNum;
- }
-
- /**
- * 获取随机字符串
- *
- * @param length
- * @return
- */
- public static String getRandomString(int length) {
- String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- Random random = new Random();
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < length; i++) {
- int number = random.nextInt(62);
- sb.append(str.charAt(number));
- }
- return sb.toString();
- }
-
-}
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/StreamUtils.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/StreamUtils.java
deleted file mode 100644
index df83a3254..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/util/StreamUtils.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package com.anji.captcha.util;
-//
-// Source code recreated from a .class file by IntelliJ IDEA
-// (powered by Fernflower decompiler)
-//
-
-import java.io.*;
-import java.nio.charset.Charset;
-
-public abstract class StreamUtils {
- public static final int BUFFER_SIZE = 4096;
- private static final byte[] EMPTY_CONTENT = new byte[0];
-
- public StreamUtils() {
- }
-
- public static byte[] copyToByteArray(InputStream in) throws IOException {
- if (in == null) {
- return new byte[0];
- } else {
- ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
- copy((InputStream) in, out);
- return out.toByteArray();
- }
- }
-
- public static String copyToString(InputStream in, Charset charset) throws IOException {
- if (in == null) {
- return "";
- } else {
- StringBuilder out = new StringBuilder();
- InputStreamReader reader = new InputStreamReader(in, charset);
- char[] buffer = new char[4096];
-
- int bytesRead;
- while ((bytesRead = reader.read(buffer)) != -1) {
- out.append(buffer, 0, bytesRead);
- }
-
- return out.toString();
- }
- }
-
- public static void copy(byte[] in, OutputStream out) throws IOException {
- out.write(in);
- }
-
- public static void copy(String in, Charset charset, OutputStream out) throws IOException {
- Writer writer = new OutputStreamWriter(out, charset);
- writer.write(in);
- writer.flush();
- }
-
- public static int copy(InputStream in, OutputStream out) throws IOException {
- int byteCount = 0;
- byte[] buffer = new byte[4096];
-
- int bytesRead;
- for (boolean var4 = true; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
- out.write(buffer, 0, bytesRead);
- }
-
- out.flush();
- return byteCount;
- }
-
- public static long copyRange(InputStream in, OutputStream out, long start, long end) throws IOException {
- long skipped = in.skip(start);
- if (skipped < start) {
- throw new IOException("Skipped only " + skipped + " bytes out of " + start + " required");
- } else {
- long bytesToCopy = end - start + 1L;
- byte[] buffer = new byte[4096];
-
- while (bytesToCopy > 0L) {
- int bytesRead = in.read(buffer);
- if (bytesRead == -1) {
- break;
- }
-
- if ((long) bytesRead <= bytesToCopy) {
- out.write(buffer, 0, bytesRead);
- bytesToCopy -= (long) bytesRead;
- } else {
- out.write(buffer, 0, (int) bytesToCopy);
- bytesToCopy = 0L;
- }
- }
-
- return end - start + 1L - bytesToCopy;
- }
- }
-
- public static int drain(InputStream in) throws IOException {
- byte[] buffer = new byte[4096];
- int byteCount;
- int bytesRead;
- for (byteCount = 0; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
- }
-
- return byteCount;
- }
-
- public static InputStream emptyInput() {
- return new ByteArrayInputStream(EMPTY_CONTENT);
- }
-
- public static InputStream nonClosing(InputStream in) {
- return new NonClosingInputStream(in);
- }
-
- public static OutputStream nonClosing(OutputStream out) {
- return new NonClosingOutputStream(out);
- }
-
- private static class NonClosingOutputStream extends FilterOutputStream {
- public NonClosingOutputStream(OutputStream out) {
- super(out);
- }
-
- public void write(byte[] b, int off, int let) throws IOException {
- this.out.write(b, off, let);
- }
-
- public void close() throws IOException {
- }
- }
-
- private static class NonClosingInputStream extends FilterInputStream {
- public NonClosingInputStream(InputStream in) {
- super(in);
- }
-
- public void close() throws IOException {
- }
- }
-}
-
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaService b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaService
deleted file mode 100644
index f31fbb43b..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/services/com.anji.captcha.service.CaptchaService
+++ /dev/null
@@ -1,3 +0,0 @@
-com.anji.captcha.service.impl.BlockPuzzleCaptchaServiceImpl
-com.anji.captcha.service.impl.ClickWordCaptchaServiceImpl
-com.anji.captcha.service.impl.DefaultCaptchaServiceImpl
\ No newline at end of file
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index 12cf6229c..8411d2cc3 100644
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1,2 +1 @@
-com.anji.captcha.config.AjCaptchaAutoConfiguration
cn.iocoder.yudao.framework.captcha.config.YudaoCaptchaConfiguration
\ No newline at end of file
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/1.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/1.png
deleted file mode 100644
index 022aabf93..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/1.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/2.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/2.png
deleted file mode 100644
index 914908e89..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/2.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/3.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/3.png
deleted file mode 100644
index f0f3ce581..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/3.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/4.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/4.png
deleted file mode 100644
index c5697f3cb..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/4.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/5.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/5.png
deleted file mode 100644
index e29e7a3c1..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/5.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/6.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/6.png
deleted file mode 100644
index 2425f412d..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/6.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/bg8.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/bg8.png
deleted file mode 100644
index 5ea54d482..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/original/bg8.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/1.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/1.png
deleted file mode 100644
index 190502660..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/1.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/2.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/2.png
deleted file mode 100644
index b1482d48b..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/2.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/3.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/3.png
deleted file mode 100644
index cdbb0b18c..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/3.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/4.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/4.png
deleted file mode 100644
index bc69c9622..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/4.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/5.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/5.png
deleted file mode 100644
index 0080a5465..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/5.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/6.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/6.png
deleted file mode 100644
index b07c3b404..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/jigsaw/slidingBlock/6.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/1.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/1.png
deleted file mode 100644
index 50dfe28ef..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/1.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/2.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/2.png
deleted file mode 100644
index 15b38ad27..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/2.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/3.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/3.png
deleted file mode 100644
index e2e487bd4..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/3.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/4.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/4.png
deleted file mode 100644
index c34baa404..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/4.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/5.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/5.png
deleted file mode 100644
index 0b3d11a27..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/5.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/6.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/6.png
deleted file mode 100644
index 67797a11d..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/6.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg10.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg10.png
deleted file mode 100644
index c99fbcb03..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg10.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg11.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg11.png
deleted file mode 100644
index 6a951d326..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg11.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg12.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg12.png
deleted file mode 100644
index a38ada504..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg12.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg13.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg13.png
deleted file mode 100644
index 07af86a86..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg13.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg14.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg14.png
deleted file mode 100644
index 95593759d..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg14.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg15.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg15.png
deleted file mode 100644
index cb1ebb63e..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg15.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg16.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg16.png
deleted file mode 100644
index 106b4562b..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg16.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg17.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg17.png
deleted file mode 100644
index bcdbe7655..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg17.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg18.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg18.png
deleted file mode 100644
index ae94e09cf..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg18.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg19.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg19.png
deleted file mode 100644
index bef9318b5..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg19.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg20.png b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg20.png
deleted file mode 100644
index 36cfbdec6..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/defaultImages/pic-click/bg20.png and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/fonts/WenQuanZhengHei.ttf b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/fonts/WenQuanZhengHei.ttf
deleted file mode 100644
index f84e9feb3..000000000
Binary files a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/fonts/WenQuanZhengHei.ttf and /dev/null differ
diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/fonts/license.txt b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/fonts/license.txt
deleted file mode 100644
index 719f68f0b..000000000
--- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/resources/fonts/license.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-文泉驿是一个开源汉字字体项目
-
-由旅美学者房骞骞(FangQ)
-
-于2004年10月创建
-
-集中力量解决GNU/Linux
-
-高质量中文字体匮乏的状况
-
-目前,文泉驿已经开发并发布了
-
-第一个完整覆盖GB18030汉字
-
-(包含27000多个汉字)
-
-的多规格点阵汉字字型文件
-
-第一个覆盖GBK字符集的
-
-开源矢量字型文件(文泉驿正黑)
-
-并提供了目前包含字符数目最多的
-
-开源字体——GNU Unifont——中
-
-绝大多数中日韩文相关的符号
-
-这些字型文件已经逐渐成为
-
-主流Linux/Unix发行版
-
-中文桌面的首选中文字体
-
-目前Ubuntu、Fedora、Slackware
-
-Magic Linux、CDLinux
-
-使用文泉驿作为默认中文字体
-
-Debian、Gentoo、Mandriva
-
-ArchLinux、Frugalware
-
-则提供了官方源支持
-
-而FreeBSD则在其ports中有提供
-
-所以,今天我们所要分享的就是
-
-文泉驿正黑体
-
-可在Linux/UNIX,Windows
-
-Mac OS和嵌入式操作系统中使用
\ No newline at end of file
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 c10e602a7..56e1ff033 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,6 +1,7 @@
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;
@@ -52,8 +53,7 @@ public class CaptchaController {
}
public static String getRemoteId(HttpServletRequest request) {
- String xfwd = request.getHeader("X-Forwarded-For");
- String ip = getRemoteIpFromXfwd(xfwd);
+ String ip = ServletUtil.getClientIP(request);
String ua = request.getHeader("user-agent");
if (StrUtil.isNotBlank(ip)) {
return ip + ua;
@@ -61,12 +61,4 @@ public class CaptchaController {
return request.getRemoteAddr() + ua;
}
- private static String getRemoteIpFromXfwd(String xfwd) {
- if (StrUtil.isNotBlank(xfwd)) {
- String[] ipList = xfwd.split(",");
- return StrUtil.trim(ipList[0]);
- }
- return null;
- }
-
}