diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 64057d679..8b10c4b23 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -49,6 +49,7 @@ 6.8.0 + 1.0.0 1.15.3 1.18.24 1.5.3.Final @@ -564,6 +565,12 @@ ${netty-all.version} + + com.xingyuv + spring-boot-starter-captcha-plus + ${captcha-plus.version} + + org.lionsoul ip2region diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/pom.xml b/yudao-framework/yudao-spring-boot-starter-captcha/pom.xml index e024e560f..b77ef8886 100644 --- a/yudao-framework/yudao-spring-boot-starter-captcha/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-captcha/pom.xml @@ -19,15 +19,13 @@ - org.springframework.boot - spring-boot-starter - provided + com.xingyuv + spring-boot-starter-captcha-plus - + org.springframework.boot - spring-boot-starter-web - provided + spring-boot-starter diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/service/RedisCaptchaServiceImpl.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/service/RedisCaptchaServiceImpl.java index c14901efb..57676f762 100644 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/service/RedisCaptchaServiceImpl.java +++ b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/cn/iocoder/yudao/framework/captcha/core/service/RedisCaptchaServiceImpl.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.framework.captcha.core.service; import com.anji.captcha.service.CaptchaCacheService; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; -import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.StringRedisTemplate; import javax.annotation.Resource; diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaAutoConfiguration.java deleted file mode 100644 index d34c4a33d..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaAutoConfiguration.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.anji.captcha.config; - -import com.anji.captcha.config.AjCaptchaServiceAutoConfiguration; -import com.anji.captcha.config.AjCaptchaStorageAutoConfiguration; -import com.anji.captcha.properties.AjCaptchaProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; - -@Configuration -@EnableConfigurationProperties(AjCaptchaProperties.class) -@ComponentScan("com.anji.captcha") -@Import({AjCaptchaServiceAutoConfiguration.class, AjCaptchaStorageAutoConfiguration.class}) -public class AjCaptchaAutoConfiguration { -} diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaServiceAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaServiceAutoConfiguration.java deleted file mode 100644 index 1ae6cf2df..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaServiceAutoConfiguration.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.anji.captcha.config; - -import cn.hutool.core.util.StrUtil; -import com.anji.captcha.model.common.Const; -import com.anji.captcha.properties.AjCaptchaProperties; -import com.anji.captcha.service.CaptchaService; -import com.anji.captcha.service.impl.CaptchaServiceFactory; -import com.anji.captcha.util.ImageUtils; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.util.Base64Utils; -import org.springframework.util.FileCopyUtils; - -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -@Slf4j -@Configuration -public class AjCaptchaServiceAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - public CaptchaService captchaService(AjCaptchaProperties prop) { - log.info("自定义配置项:{}", prop.toString()); - Properties config = new Properties(); - config.put(Const.CAPTCHA_CACHETYPE, prop.getCacheType().name()); - config.put(Const.CAPTCHA_WATER_MARK, prop.getWaterMark()); - config.put(Const.CAPTCHA_FONT_TYPE, prop.getFontType()); - config.put(Const.CAPTCHA_TYPE, prop.getType().getCodeValue()); - config.put(Const.CAPTCHA_INTERFERENCE_OPTIONS, prop.getInterferenceOptions()); - config.put(Const.ORIGINAL_PATH_JIGSAW, prop.getJigsaw()); - config.put(Const.ORIGINAL_PATH_PIC_CLICK, prop.getPicClick()); - config.put(Const.CAPTCHA_SLIP_OFFSET, prop.getSlipOffset()); - config.put(Const.CAPTCHA_AES_STATUS, String.valueOf(prop.getAesStatus())); - config.put(Const.CAPTCHA_WATER_FONT, prop.getWaterFont()); - config.put(Const.CAPTCHA_CACAHE_MAX_NUMBER, prop.getCacheNumber()); - config.put(Const.CAPTCHA_TIMING_CLEAR_SECOND, prop.getTimingClear()); - - config.put(Const.HISTORY_DATA_CLEAR_ENABLE, prop.isHistoryDataClearEnable() ? "1" : "0"); - - config.put(Const.REQ_FREQUENCY_LIMIT_ENABLE, prop.getReqFrequencyLimitEnable() ? "1" : "0"); - config.put(Const.REQ_GET_LOCK_LIMIT, prop.getReqGetLockLimit() + ""); - config.put(Const.REQ_GET_LOCK_SECONDS, prop.getReqGetLockSeconds() + ""); - config.put(Const.REQ_GET_MINUTE_LIMIT, prop.getReqGetMinuteLimit() + ""); - config.put(Const.REQ_CHECK_MINUTE_LIMIT, prop.getReqCheckMinuteLimit() + ""); - config.put(Const.REQ_VALIDATE_MINUTE_LIMIT, prop.getReqVerifyMinuteLimit() + ""); - - config.put(Const.CAPTCHA_FONT_SIZE, prop.getFontSize() + ""); - config.put(Const.CAPTCHA_FONT_STYLE, prop.getFontStyle() + ""); - config.put(Const.CAPTCHA_WORD_COUNT, prop.getClickWordCount() + ""); - - if ((StrUtil.isNotBlank(prop.getJigsaw()) && prop.getJigsaw().startsWith("classpath:")) - || (StrUtil.isNotBlank(prop.getPicClick()) && prop.getPicClick().startsWith("classpath:"))) { - //自定义resources目录下初始化底图 - config.put(Const.CAPTCHA_INIT_ORIGINAL, "true"); - initializeBaseMap(prop.getJigsaw(), prop.getPicClick()); - } - return CaptchaServiceFactory.getInstance(config); - } - - private static void initializeBaseMap(String jigsaw, String picClick) { - ImageUtils.cacheBootImage(getResourcesImagesFile(jigsaw + "/original/*.png"), - getResourcesImagesFile(jigsaw + "/slidingBlock/*.png"), - getResourcesImagesFile(picClick + "/*.png")); - } - - public static Map getResourcesImagesFile(String path) { - Map imgMap = new HashMap<>(); - ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); - try { - Resource[] resources = resolver.getResources(path); - for (Resource resource : resources) { - byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream()); - String string = Base64Utils.encodeToString(bytes); - String filename = resource.getFilename(); - imgMap.put(filename, string); - } - } catch (Exception e) { - e.printStackTrace(); - } - return imgMap; - } -} diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaStorageAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaStorageAutoConfiguration.java deleted file mode 100644 index 0eed5316c..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/config/AjCaptchaStorageAutoConfiguration.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.anji.captcha.config; - -import com.anji.captcha.properties.AjCaptchaProperties; -import com.anji.captcha.service.CaptchaCacheService; -import com.anji.captcha.service.impl.CaptchaServiceFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * 存储策略自动配置. - */ -@Configuration -public class AjCaptchaStorageAutoConfiguration { - - @Bean(name = "AjCaptchaCacheService") - public CaptchaCacheService captchaCacheService(AjCaptchaProperties ajCaptchaProperties) { - // 缓存类型redis/local/.... - return CaptchaServiceFactory.getCache(ajCaptchaProperties.getCacheType().name()); - } -} diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/CaptchaBaseMapEnum.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/CaptchaBaseMapEnum.java deleted file mode 100644 index 52d6a18af..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/CaptchaBaseMapEnum.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.anji.captcha.model.common; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 底图类型枚举 - */ -@Getter -@AllArgsConstructor -public enum CaptchaBaseMapEnum { - ORIGINAL("ORIGINAL", "滑动拼图底图"), - SLIDING_BLOCK("SLIDING_BLOCK", "滑动拼图滑块底图"), - PIC_CLICK("PIC_CLICK", "文字点选底图"); - - private final String codeValue; - private final String codeDesc; - - //根据codeValue获取枚举 - public static CaptchaBaseMapEnum parseFromCodeValue(String codeValue) { - for (CaptchaBaseMapEnum e : CaptchaBaseMapEnum.values()) { - if (e.codeValue.equals(codeValue)) { - return e; - } - } - return null; - } - - //根据codeValue获取描述 - public static String getCodeDescByCodeBalue(String codeValue) { - CaptchaBaseMapEnum enumItem = parseFromCodeValue(codeValue); - return enumItem == null ? "" : enumItem.getCodeDesc(); - } - - //验证codeValue是否有效 - public static boolean validateCodeValue(String codeValue) { - return parseFromCodeValue(codeValue) != null; - } - - //列出所有值字符串 - public static String getString() { - StringBuffer buffer = new StringBuffer(); - for (CaptchaBaseMapEnum e : CaptchaBaseMapEnum.values()) { - buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", "); - } - buffer.deleteCharAt(buffer.lastIndexOf(",")); - return buffer.toString().trim(); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/CaptchaTypeEnum.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/CaptchaTypeEnum.java deleted file mode 100644 index fce123f58..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/CaptchaTypeEnum.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.anji.captcha.model.common; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -public enum CaptchaTypeEnum { - /** - * 滑块拼图. - */ - BLOCKPUZZLE("blockPuzzle", "滑块拼图"), - /** - * 文字点选. - */ - CLICKWORD("clickWord", "文字点选"), - /** - * 默认. - */ - DEFAULT("default", "默认"); - - private final String codeValue; - private final String codeDesc; - - //根据codeValue获取枚举 - public static CaptchaTypeEnum parseFromCodeValue(String codeValue) { - for (CaptchaTypeEnum e : CaptchaTypeEnum.values()) { - if (e.codeValue.equals(codeValue)) { - return e; - } - } - return null; - } - - //根据codeValue获取描述 - public static String getCodeDescByCodeBalue(String codeValue) { - CaptchaTypeEnum enumItem = parseFromCodeValue(codeValue); - return enumItem == null ? "" : enumItem.getCodeDesc(); - } - - //验证codeValue是否有效 - public static boolean validateCodeValue(String codeValue) { - return parseFromCodeValue(codeValue) != null; - } - - //列出所有值字符串 - public static String getString() { - StringBuilder buffer = new StringBuilder(); - for (CaptchaTypeEnum e : CaptchaTypeEnum.values()) { - buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", "); - } - buffer.deleteCharAt(buffer.lastIndexOf(",")); - return buffer.toString().trim(); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/Const.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/Const.java deleted file mode 100644 index 782a6e39f..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/Const.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.anji.captcha.model.common; - -/*** - * @author wongbin - */ -public interface Const { - - /** - * 滑块底图路径 - */ - String ORIGINAL_PATH_JIGSAW = "captcha.captchaOriginalPath.jigsaw"; - - /*** - *点选底图路径 - */ - String ORIGINAL_PATH_PIC_CLICK = "captcha.captchaOriginalPath.pic-click"; - - /** - * 缓存local/redis... - */ - String CAPTCHA_CACHETYPE = "captcha.cacheType"; - - /** - * 右下角水印文字(我的水印) - */ - String CAPTCHA_WATER_MARK = "captcha.water.mark"; - - /** - * 点选文字验证码的文字字体(宋体) - */ - String CAPTCHA_FONT_TYPE = "captcha.font.type"; - String CAPTCHA_FONT_STYLE = "captcha.font.style"; - String CAPTCHA_FONT_SIZE = "captcha.font.size"; - - /** - * 验证码类型default两种都实例化。 - */ - String CAPTCHA_TYPE = "captcha.type"; - - /** - * 滑动干扰项(0/1/2) - */ - String CAPTCHA_INTERFERENCE_OPTIONS = "captcha.interference.options"; - - /** - * 底图自定义初始化 - */ - String CAPTCHA_INIT_ORIGINAL = "captcha.init.original"; - - /** - * 滑动误差偏移量 - */ - String CAPTCHA_SLIP_OFFSET = "captcha.slip.offset"; - - /** - * aes加密开关 - */ - String CAPTCHA_AES_STATUS = "captcha.aes.status"; - - /** - * 右下角水印字体(宋体) - */ - String CAPTCHA_WATER_FONT = "captcha.water.font"; - - /** - * local缓存的阈值 - */ - String CAPTCHA_CACAHE_MAX_NUMBER = "captcha.cache.number"; - - /** - * 定时清理过期local缓存,秒 - */ - String CAPTCHA_TIMING_CLEAR_SECOND = "captcha.timing.clear"; - - /** - * 历史资源清除开关 0禁用,1 开启 - */ - String HISTORY_DATA_CLEAR_ENABLE = "captcha.history.data.clear.enable"; - - /** - * 接口限流开关 0禁用 1启用 - */ - String REQ_FREQUENCY_LIMIT_ENABLE = "captcha.req.frequency.limit.enable"; - - /** - * get 接口 一分钟请求次数限制 - */ - String REQ_GET_MINUTE_LIMIT = "captcha.req.get.minute.limit"; - - /** - * 验证失败后,get接口锁定时间 - */ - String REQ_GET_LOCK_LIMIT = "captcha.req.get.lock.limit"; - /** - * 验证失败后,get接口锁定时间 - */ - String REQ_GET_LOCK_SECONDS = "captcha.req.get.lock.seconds"; - - /** - * verify 接口 一分钟请求次数限制 - */ - String REQ_VALIDATE_MINUTE_LIMIT = "captcha.req.verify.minute.limit"; - /** - * check接口 一分钟请求次数限制 - */ - String REQ_CHECK_MINUTE_LIMIT = "captcha.req.check.minute.limit"; - - /*** - * 点选文字个数 - */ - String CAPTCHA_WORD_COUNT = "captcha.word.count"; -} diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/RepCodeEnum.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/RepCodeEnum.java deleted file mode 100644 index 2fcb651a7..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/RepCodeEnum.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - *Copyright © 2018 anji-plus - *安吉加加信息技术有限公司 - *http://www.anji-plus.com - *All rights reserved. - */ -package com.anji.captcha.model.common; - -import com.anji.captcha.model.common.ResponseModel; -import lombok.AllArgsConstructor; -import lombok.Getter; - -import java.text.MessageFormat; - -/** - * 返回应答码 - * - * @author - */ -@AllArgsConstructor -@Getter -public enum RepCodeEnum { - - /** - * 0001 - 0099 网关应答码 - */ - SUCCESS("0000", "成功"), - ERROR("0001", "操作失败"), - EXCEPTION("9999", "服务器内部异常"), - - BLANK_ERROR("0011", "{0}不能为空"), - NULL_ERROR("0011", "{0}不能为空"), - NOT_NULL_ERROR("0012", "{0}必须为空"), - NOT_EXIST_ERROR("0013", "{0}数据库中不存在"), - EXIST_ERROR("0014", "{0}数据库中已存在"), - PARAM_TYPE_ERROR("0015", "{0}类型错误"), - PARAM_FORMAT_ERROR("0016", "{0}格式错误"), - - API_CAPTCHA_INVALID("6110", "验证码已失效,请重新获取"), - API_CAPTCHA_COORDINATE_ERROR("6111", "验证失败"), - API_CAPTCHA_ERROR("6112", "获取验证码失败,请联系管理员"), - API_CAPTCHA_BASEMAP_NULL("6113", "底图未初始化成功,请检查路径"), - - API_REQ_LIMIT_GET_ERROR("6201", "get接口请求次数超限,请稍后再试!"), - API_REQ_INVALID("6206", "无效请求,请重新获取验证码"), - API_REQ_LOCK_GET_ERROR("6202", "接口验证失败数过多,请稍后再试"), - API_REQ_LIMIT_CHECK_ERROR("6204", "check接口请求次数超限,请稍后再试!"), - API_REQ_LIMIT_VERIFY_ERROR("6205", "verify请求次数超限!"); - private final String code; - private final String desc; - - - /** - * 将入参fieldNames与this.desc组合成错误信息 - * {fieldName}不能为空 - * - * @param fieldNames - * @return - */ - public com.anji.captcha.model.common.ResponseModel parseError(Object... fieldNames) { - com.anji.captcha.model.common.ResponseModel errorMessage = new ResponseModel(); - String newDesc = MessageFormat.format(this.desc, fieldNames); - - errorMessage.setRepCode(this.code); - errorMessage.setRepMsg(newDesc); - return errorMessage; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/RequestModel.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/RequestModel.java deleted file mode 100644 index 87104d341..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/RequestModel.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - *Copyright © 2018 anji-plus - *安吉加加信息技术有限公司 - *http://www.anji-plus.com - *All rights reserved. - */ -package com.anji.captcha.model.common; - - -import cn.hutool.core.util.StrUtil; -import lombok.Data; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.List; - -@Data -public class RequestModel implements Serializable { - - private static final long serialVersionUID = -5800786065305114784L; - - /** - * 当前请求接口路径 /business/accessUser/login - */ - private String servletPath; - - /** - * {"reqData":{"password":"*****","userName":"admin"},"sign":"a304a7f296f565b6d2009797f68180f0","time":"1542456453355","token":""} - */ - private String requestString; - - /** - * {"password":"****","userName":"admin"} - */ - private HashMap reqData; - - private String token; - - private Long userId; - - private String userName; - - private List projectList; - - //拥有哪些分组 - private List groupIdList; - - private String target; - - private String sign; - - private String time; - - private String sourceIP; - - /** - * 校验自身参数合法性 - * - * @return - */ - public boolean isVaildateRequest() { - if (StrUtil.isBlank(sign) || StrUtil.isBlank(time)) { - return false; - } - return true; - } - - public String getServletPath() { - return servletPath; - } - - public void setServletPath(String servletPath) { - this.servletPath = servletPath; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/ResponseModel.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/ResponseModel.java deleted file mode 100644 index 39e02d177..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/common/ResponseModel.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - *Copyright © 2018 anji-plus - *安吉加加信息技术有限公司 - *http://www.anji-plus.com - *All rights reserved. - */ -package com.anji.captcha.model.common; - -import cn.hutool.core.util.StrUtil; -import lombok.Data; - -import java.io.Serializable; - -@Data -public class ResponseModel implements Serializable { - - private static final long serialVersionUID = 8445617032523881407L; - - private String repCode; - - private String repMsg; - - private Object repData; - - public ResponseModel() { - this.repCode = RepCodeEnum.SUCCESS.getCode(); - } - - public ResponseModel(RepCodeEnum repCodeEnum) { - this.setRepCodeEnum(repCodeEnum); - } - - //成功 - public static ResponseModel success() { - return ResponseModel.successMsg("成功"); - } - - public static ResponseModel successMsg(String message) { - ResponseModel responseModel = new ResponseModel(); - responseModel.setRepMsg(message); - return responseModel; - } - - public static ResponseModel successData(Object data) { - ResponseModel responseModel = new ResponseModel(); - responseModel.setRepCode(RepCodeEnum.SUCCESS.getCode()); - responseModel.setRepData(data); - return responseModel; - } - - //失败 - public static ResponseModel errorMsg(RepCodeEnum message) { - ResponseModel responseModel = new ResponseModel(); - responseModel.setRepCodeEnum(message); - return responseModel; - } - - public static ResponseModel errorMsg(String message) { - ResponseModel responseModel = new ResponseModel(); - responseModel.setRepCode(RepCodeEnum.ERROR.getCode()); - responseModel.setRepMsg(message); - return responseModel; - } - - public static ResponseModel errorMsg(RepCodeEnum repCodeEnum, String message) { - ResponseModel responseModel = new ResponseModel(); - responseModel.setRepCode(repCodeEnum.getCode()); - responseModel.setRepMsg(message); - return responseModel; - } - - public static ResponseModel exceptionMsg(String message) { - ResponseModel responseModel = new ResponseModel(); - responseModel.setRepCode(RepCodeEnum.EXCEPTION.getCode()); - responseModel.setRepMsg(RepCodeEnum.EXCEPTION.getDesc() + ": " + message); - return responseModel; - } - - - public boolean isSuccess() { - return StrUtil.equals(repCode, RepCodeEnum.SUCCESS.getCode()); - } - - public String getRepCode() { - return repCode; - } - - public void setRepCodeEnum(RepCodeEnum repCodeEnum) { - this.repCode = repCodeEnum.getCode(); - this.repMsg = repCodeEnum.getDesc(); - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/vo/CaptchaVO.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/vo/CaptchaVO.java deleted file mode 100644 index 4fe243b91..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/vo/CaptchaVO.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - *Copyright © 2018 anji-plus - *安吉加加信息技术有限公司 - *http://www.anji-plus.com - *All rights reserved. - */ -package com.anji.captcha.model.vo; - -import com.anji.captcha.model.vo.PointVO; -import lombok.Data; - -import java.awt.*; -import java.io.Serializable; -import java.util.List; - -@Data -public class CaptchaVO implements Serializable { - - /** - * 验证码id(后台申请) - */ - private String captchaId; - - private String projectCode; - - /** - * 验证码类型:(clickWord,blockPuzzle) - */ - private String captchaType; - - private String captchaOriginalPath; - - private String captchaFontType; - - private Integer captchaFontSize; - - private String secretKey; - - /** - * 原生图片base64 - */ - private String originalImageBase64; - - /** - * 滑块点选坐标 - */ - private PointVO point; - - /** - * 滑块图片base64 - */ - private String jigsawImageBase64; - - /** - * 点选文字 - */ - private List wordList; - - /** - * 点选坐标 - */ - private List pointList; - - - /** - * 点坐标(base64加密传输) - */ - private String pointJson; - - - /** - * UUID(每次请求的验证码唯一标识) - */ - private String token; - - /** - * 校验结果 - */ - private Boolean result = false; - - /** - * 后台二次校验参数 - */ - private String captchaVerification; - - /*** - * 客户端UI组件id,组件初始化时设置一次,UUID - */ - private String clientUid; - /*** - * 客户端的请求时间,预留字段 - */ - private Long ts; - - /*** - * 客户端ip+userAgent - */ - private String browserInfo; - - public void resetClientFlag() { - this.browserInfo = null; - this.clientUid = null; - } - -} diff --git a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/vo/PointVO.java b/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/vo/PointVO.java deleted file mode 100644 index d0cf70252..000000000 --- a/yudao-framework/yudao-spring-boot-starter-captcha/src/main/java/com/anji/captcha/model/vo/PointVO.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.anji.captcha.model.vo; - -import lombok.Data; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -/** - * Created by raodeming on 2020/5/16. - */ -@Data -public class PointVO { - private String secretKey; - - public int x; - - public int y; - - public PointVO(int x, int y, String secretKey) { - this.secretKey = secretKey; - this.x = x; - this.y = y; - } - - public PointVO() { - } - - public PointVO(int x, int y) { - this.x = x; - this.y = y; - } - - public String toJsonString() { - return String.format("{\"secretKey\":\"%s\",\"x\":%d,\"y\":%d}", secretKey, x, y); - } - - public PointVO parse(String jsonStr) { - Map 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; - } - }