refactor: captcha-plus
@ -1,14 +0,0 @@
|
||||
package com.anji.captcha.config;
|
||||
|
||||
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 {
|
||||
}
|
||||
@ -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<String, String> getResourcesImagesFile(String path) {
|
||||
Map<String, String> 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;
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<Long> projectList;
|
||||
|
||||
//拥有哪些分组
|
||||
private List<Long> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,74 +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;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 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<String, Object> 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);
|
||||
}
|
||||
}
|
||||
@ -1,100 +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 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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,120 +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.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<String, String> originalCacheMap = new ConcurrentHashMap(); //滑块底图
|
||||
private static Map<String, String> slidingBlockCacheMap = new ConcurrentHashMap(); //滑块
|
||||
private static Map<String, String> picClickCacheMap = new ConcurrentHashMap(); //点选文字
|
||||
private static Map<String, String[]> 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<String, String> originalMap, Map<String, String> slidingBlockMap, Map<String, String> 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 = 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 = 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<String, String> getResourcesImagesFile(String path) {
|
||||
//默认提供六张底图
|
||||
Map<String, String> 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<String, String> getImagesFile(String path) {
|
||||
Map<String, String> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
com.anji.captcha.service.impl.BlockPuzzleCaptchaServiceImpl
|
||||
com.anji.captcha.service.impl.ClickWordCaptchaServiceImpl
|
||||
com.anji.captcha.service.impl.DefaultCaptchaServiceImpl
|
||||
@ -1,2 +1 @@
|
||||
com.anji.captcha.config.AjCaptchaAutoConfiguration
|
||||
cn.iocoder.yudao.framework.captcha.config.YudaoCaptchaConfiguration
|
||||
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 58 KiB |