修改 使用hutool验证码替换原验证码
parent
63aedd6fe9
commit
6726e7716e
|
|
@ -49,8 +49,16 @@ spring:
|
||||||
security:
|
security:
|
||||||
# 验证码
|
# 验证码
|
||||||
captcha:
|
captcha:
|
||||||
|
# 是否开启验证码
|
||||||
enabled: true
|
enabled: true
|
||||||
type: math
|
# 验证码类型 math 数组计算 char 字符验证
|
||||||
|
type: MATH
|
||||||
|
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
|
||||||
|
category: CIRCLE
|
||||||
|
# 数字验证码位数
|
||||||
|
numberLength: 1
|
||||||
|
# 字符验证码长度
|
||||||
|
charLength: 4
|
||||||
# 防止XSS攻击
|
# 防止XSS攻击
|
||||||
xss:
|
xss:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,16 @@
|
||||||
package com.ruoyi.common.core.utils.reflect;
|
package com.ruoyi.common.core.utils.reflect;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import com.ruoyi.common.core.text.Convert;
|
||||||
import java.lang.reflect.Method;
|
import com.ruoyi.common.core.utils.DateUtils;
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Date;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.poi.ss.usermodel.DateUtil;
|
import org.apache.poi.ss.usermodel.DateUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import com.ruoyi.common.core.text.Convert;
|
|
||||||
import com.ruoyi.common.core.utils.DateUtils;
|
import java.lang.reflect.*;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
|
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
|
||||||
|
|
@ -21,7 +18,7 @@ import com.ruoyi.common.core.utils.DateUtils;
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public class ReflectUtils
|
public class ReflectUtils extends ReflectUtil
|
||||||
{
|
{
|
||||||
private static final String SETTER_PREFIX = "set";
|
private static final String SETTER_PREFIX = "set";
|
||||||
|
|
||||||
|
|
@ -70,52 +67,6 @@ public class ReflectUtils
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <E> E getFieldValue(final Object obj, final String fieldName)
|
|
||||||
{
|
|
||||||
Field field = getAccessibleField(obj, fieldName);
|
|
||||||
if (field == null)
|
|
||||||
{
|
|
||||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
E result = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = (E) field.get(obj);
|
|
||||||
}
|
|
||||||
catch (IllegalAccessException e)
|
|
||||||
{
|
|
||||||
logger.error("不可能抛出的异常{}", e.getMessage());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
|
|
||||||
*/
|
|
||||||
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
|
|
||||||
{
|
|
||||||
Field field = getAccessibleField(obj, fieldName);
|
|
||||||
if (field == null)
|
|
||||||
{
|
|
||||||
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
|
||||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
field.set(obj, value);
|
|
||||||
}
|
|
||||||
catch (IllegalAccessException e)
|
|
||||||
{
|
|
||||||
logger.error("不可能抛出的异常: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 直接调用对象方法, 无视private/protected修饰符.
|
* 直接调用对象方法, 无视private/protected修饰符.
|
||||||
* 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
|
* 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
|
||||||
|
|
|
||||||
|
|
@ -58,12 +58,6 @@
|
||||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--验证码 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.penggle</groupId>
|
|
||||||
<artifactId>kaptcha</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- RuoYi Common Redis-->
|
<!-- RuoYi Common Redis-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ruoyi</groupId>
|
<groupId>com.ruoyi</groupId>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
package com.ruoyi.gateway.captcha;
|
||||||
|
|
||||||
|
import cn.hutool.captcha.generator.CodeGenerator;
|
||||||
|
import cn.hutool.core.math.Calculator;
|
||||||
|
import cn.hutool.core.util.CharUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import com.ruoyi.common.core.utils.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 无符号计算生成器
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
public class UnsignedMathGenerator implements CodeGenerator {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -5514819971774091076L;
|
||||||
|
|
||||||
|
private static final String operators = "+-*";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参与计算数字最大长度
|
||||||
|
*/
|
||||||
|
private final int numberLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*/
|
||||||
|
public UnsignedMathGenerator() {
|
||||||
|
this(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param numberLength 参与计算最大数字位数
|
||||||
|
*/
|
||||||
|
public UnsignedMathGenerator(int numberLength) {
|
||||||
|
this.numberLength = numberLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generate() {
|
||||||
|
final int limit = getLimit();
|
||||||
|
int min = RandomUtil.randomInt(limit);
|
||||||
|
int max = RandomUtil.randomInt(min, limit);
|
||||||
|
String number1 = Integer.toString(max);
|
||||||
|
String number2 = Integer.toString(min);
|
||||||
|
number1 = StringUtils.rightPad(number1, this.numberLength, CharUtil.SPACE);
|
||||||
|
number2 = StringUtils.rightPad(number2, this.numberLength, CharUtil.SPACE);
|
||||||
|
|
||||||
|
return number1 + RandomUtil.randomChar(operators) + number2 + '=';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verify(String code, String userInputCode) {
|
||||||
|
int result;
|
||||||
|
try {
|
||||||
|
result = Integer.parseInt(userInputCode);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// 用户输入非数字
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int calculateResult = (int) Calculator.conversion(code);
|
||||||
|
return result == calculateResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验证码长度
|
||||||
|
*
|
||||||
|
* @return 验证码长度
|
||||||
|
*/
|
||||||
|
public int getLength() {
|
||||||
|
return this.numberLength * 2 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据长度获取参与计算数字最大值
|
||||||
|
*
|
||||||
|
* @return 最大值
|
||||||
|
*/
|
||||||
|
private int getLimit() {
|
||||||
|
return Integer.parseInt("1" + StringUtils.repeat('0', this.numberLength));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,83 +1,62 @@
|
||||||
package com.ruoyi.gateway.config;
|
package com.ruoyi.gateway.config;
|
||||||
|
|
||||||
import java.util.Properties;
|
import cn.hutool.captcha.CaptchaUtil;
|
||||||
|
import cn.hutool.captcha.CircleCaptcha;
|
||||||
|
import cn.hutool.captcha.LineCaptcha;
|
||||||
|
import cn.hutool.captcha.ShearCaptcha;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import com.google.code.kaptcha.impl.DefaultKaptcha;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import com.google.code.kaptcha.util.Config;
|
|
||||||
import static com.google.code.kaptcha.Constants.*;
|
import java.awt.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码配置
|
* 验证码配置
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author Lion Li
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
public class CaptchaConfig
|
public class CaptchaConfig {
|
||||||
{
|
|
||||||
@Bean(name = "captchaProducer")
|
private final int width = 160;
|
||||||
public DefaultKaptcha getKaptchaBean()
|
private final int height = 60;
|
||||||
{
|
private final Color background = Color.PINK;
|
||||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
private final Font font = new Font("Arial", Font.BOLD, 48);
|
||||||
Properties properties = new Properties();
|
|
||||||
// 是否有边框 默认为true 我们可以自己设置yes,no
|
/**
|
||||||
properties.setProperty(KAPTCHA_BORDER, "yes");
|
* 圆圈干扰验证码
|
||||||
// 验证码文本字符颜色 默认为Color.BLACK
|
*/
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
|
@Lazy
|
||||||
// 验证码图片宽度 默认为200
|
@Bean
|
||||||
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
|
public CircleCaptcha circleCaptcha() {
|
||||||
// 验证码图片高度 默认为50
|
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(width, height);
|
||||||
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
|
captcha.setBackground(background);
|
||||||
// 验证码文本字符大小 默认为40
|
captcha.setFont(font);
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
|
return captcha;
|
||||||
// KAPTCHA_SESSION_KEY
|
|
||||||
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
|
|
||||||
// 验证码文本字符长度 默认为5
|
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
|
|
||||||
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
|
|
||||||
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
|
|
||||||
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
|
|
||||||
Config config = new Config(properties);
|
|
||||||
defaultKaptcha.setConfig(config);
|
|
||||||
return defaultKaptcha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "captchaProducerMath")
|
/**
|
||||||
public DefaultKaptcha getKaptchaBeanMath()
|
* 线段干扰的验证码
|
||||||
{
|
*/
|
||||||
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
|
@Lazy
|
||||||
Properties properties = new Properties();
|
@Bean
|
||||||
// 是否有边框 默认为true 我们可以自己设置yes,no
|
public LineCaptcha lineCaptcha() {
|
||||||
properties.setProperty(KAPTCHA_BORDER, "yes");
|
LineCaptcha captcha = CaptchaUtil.createLineCaptcha(width, height);
|
||||||
// 边框颜色 默认为Color.BLACK
|
captcha.setBackground(background);
|
||||||
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
|
captcha.setFont(font);
|
||||||
// 验证码文本字符颜色 默认为Color.BLACK
|
return captcha;
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
|
|
||||||
// 验证码图片宽度 默认为200
|
|
||||||
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
|
|
||||||
// 验证码图片高度 默认为50
|
|
||||||
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
|
|
||||||
// 验证码文本字符大小 默认为40
|
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
|
|
||||||
// KAPTCHA_SESSION_KEY
|
|
||||||
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
|
|
||||||
// 验证码文本生成器
|
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.gateway.config.KaptchaTextCreator");
|
|
||||||
// 验证码文本字符间距 默认为2
|
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
|
|
||||||
// 验证码文本字符长度 默认为5
|
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
|
|
||||||
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
|
|
||||||
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
|
|
||||||
// 验证码噪点颜色 默认为Color.BLACK
|
|
||||||
properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
|
|
||||||
// 干扰实现类
|
|
||||||
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
|
|
||||||
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
|
|
||||||
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
|
|
||||||
Config config = new Config(properties);
|
|
||||||
defaultKaptcha.setConfig(config);
|
|
||||||
return defaultKaptcha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扭曲干扰验证码
|
||||||
|
*/
|
||||||
|
@Lazy
|
||||||
|
@Bean
|
||||||
|
public ShearCaptcha shearCaptcha() {
|
||||||
|
ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(width, height);
|
||||||
|
captcha.setBackground(background);
|
||||||
|
captcha.setFont(font);
|
||||||
|
return captcha;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
package com.ruoyi.gateway.config;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码文本生成器
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class KaptchaTextCreator extends DefaultTextCreator
|
|
||||||
{
|
|
||||||
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getText()
|
|
||||||
{
|
|
||||||
Integer result = 0;
|
|
||||||
Random random = new Random();
|
|
||||||
int x = random.nextInt(10);
|
|
||||||
int y = random.nextInt(10);
|
|
||||||
StringBuilder suChinese = new StringBuilder();
|
|
||||||
int randomoperands = (int) Math.round(Math.random() * 2);
|
|
||||||
if (randomoperands == 0)
|
|
||||||
{
|
|
||||||
result = x * y;
|
|
||||||
suChinese.append(CNUMBERS[x]);
|
|
||||||
suChinese.append("*");
|
|
||||||
suChinese.append(CNUMBERS[y]);
|
|
||||||
}
|
|
||||||
else if (randomoperands == 1)
|
|
||||||
{
|
|
||||||
if (!(x == 0) && y % x == 0)
|
|
||||||
{
|
|
||||||
result = y / x;
|
|
||||||
suChinese.append(CNUMBERS[y]);
|
|
||||||
suChinese.append("/");
|
|
||||||
suChinese.append(CNUMBERS[x]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = x + y;
|
|
||||||
suChinese.append(CNUMBERS[x]);
|
|
||||||
suChinese.append("+");
|
|
||||||
suChinese.append(CNUMBERS[y]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (randomoperands == 2)
|
|
||||||
{
|
|
||||||
if (x >= y)
|
|
||||||
{
|
|
||||||
result = x - y;
|
|
||||||
suChinese.append(CNUMBERS[x]);
|
|
||||||
suChinese.append("-");
|
|
||||||
suChinese.append(CNUMBERS[y]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = y - x;
|
|
||||||
suChinese.append(CNUMBERS[y]);
|
|
||||||
suChinese.append("-");
|
|
||||||
suChinese.append(CNUMBERS[x]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = x + y;
|
|
||||||
suChinese.append(CNUMBERS[x]);
|
|
||||||
suChinese.append("+");
|
|
||||||
suChinese.append(CNUMBERS[y]);
|
|
||||||
}
|
|
||||||
suChinese.append("=?@" + result);
|
|
||||||
return suChinese.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package com.ruoyi.gateway.config.properties;
|
package com.ruoyi.gateway.config.properties;
|
||||||
|
|
||||||
|
import com.ruoyi.gateway.enums.CaptchaCategory;
|
||||||
|
import com.ruoyi.gateway.enums.CaptchaType;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||||
|
|
@ -16,14 +18,29 @@ import org.springframework.context.annotation.Configuration;
|
||||||
@ConfigurationProperties(prefix = "security.captcha")
|
@ConfigurationProperties(prefix = "security.captcha")
|
||||||
public class CaptchaProperties
|
public class CaptchaProperties
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* 验证码类型
|
||||||
|
*/
|
||||||
|
private CaptchaType type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码类别
|
||||||
|
*/
|
||||||
|
private CaptchaCategory category;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数字验证码位数
|
||||||
|
*/
|
||||||
|
private Integer numberLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符验证码长度
|
||||||
|
*/
|
||||||
|
private Integer charLength;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码开关
|
* 验证码开关
|
||||||
*/
|
*/
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码类型(math 数组计算 char 字符)
|
|
||||||
*/
|
|
||||||
private String type;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.ruoyi.gateway.enums;
|
||||||
|
|
||||||
|
import cn.hutool.captcha.AbstractCaptcha;
|
||||||
|
import cn.hutool.captcha.CircleCaptcha;
|
||||||
|
import cn.hutool.captcha.LineCaptcha;
|
||||||
|
import cn.hutool.captcha.ShearCaptcha;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码类别
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum CaptchaCategory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线段干扰
|
||||||
|
*/
|
||||||
|
LINE(LineCaptcha.class),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 圆圈干扰
|
||||||
|
*/
|
||||||
|
CIRCLE(CircleCaptcha.class),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 扭曲干扰
|
||||||
|
*/
|
||||||
|
SHEAR(ShearCaptcha.class);
|
||||||
|
|
||||||
|
private final Class<? extends AbstractCaptcha> clazz;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.ruoyi.gateway.enums;
|
||||||
|
|
||||||
|
import cn.hutool.captcha.generator.CodeGenerator;
|
||||||
|
import cn.hutool.captcha.generator.RandomGenerator;
|
||||||
|
import com.ruoyi.gateway.captcha.UnsignedMathGenerator;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证码类型
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum CaptchaType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数字
|
||||||
|
*/
|
||||||
|
MATH(UnsignedMathGenerator.class),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符
|
||||||
|
*/
|
||||||
|
CHAR(RandomGenerator.class);
|
||||||
|
|
||||||
|
private final Class<? extends CodeGenerator> clazz;
|
||||||
|
}
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
package com.ruoyi.gateway.service.impl;
|
package com.ruoyi.gateway.service.impl;
|
||||||
|
|
||||||
import com.google.code.kaptcha.Producer;
|
import cn.hutool.captcha.AbstractCaptcha;
|
||||||
|
import cn.hutool.captcha.generator.CodeGenerator;
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
import com.ruoyi.common.core.constant.Constants;
|
import com.ruoyi.common.core.constant.Constants;
|
||||||
import com.ruoyi.common.core.exception.CaptchaException;
|
import com.ruoyi.common.core.exception.CaptchaException;
|
||||||
import com.ruoyi.common.core.utils.IdUtils;
|
import com.ruoyi.common.core.utils.IdUtils;
|
||||||
|
import com.ruoyi.common.core.utils.SpringUtils;
|
||||||
import com.ruoyi.common.core.utils.StringUtils;
|
import com.ruoyi.common.core.utils.StringUtils;
|
||||||
import com.ruoyi.common.core.utils.sign.Base64;
|
import com.ruoyi.common.core.utils.reflect.ReflectUtils;
|
||||||
import com.ruoyi.common.core.web.domain.AjaxResult;
|
import com.ruoyi.common.core.web.domain.AjaxResult;
|
||||||
import com.ruoyi.common.redis.utils.RedisUtils;
|
import com.ruoyi.common.redis.utils.RedisUtils;
|
||||||
import com.ruoyi.gateway.config.properties.CaptchaProperties;
|
import com.ruoyi.gateway.config.properties.CaptchaProperties;
|
||||||
|
import com.ruoyi.gateway.enums.CaptchaType;
|
||||||
import com.ruoyi.gateway.service.ValidateCodeService;
|
import com.ruoyi.gateway.service.ValidateCodeService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.FastByteArrayOutputStream;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
@ -28,12 +28,6 @@ import java.util.concurrent.TimeUnit;
|
||||||
@Service
|
@Service
|
||||||
public class ValidateCodeServiceImpl implements ValidateCodeService
|
public class ValidateCodeServiceImpl implements ValidateCodeService
|
||||||
{
|
{
|
||||||
@Resource(name = "captchaProducer")
|
|
||||||
private Producer captchaProducer;
|
|
||||||
|
|
||||||
@Resource(name = "captchaProducerMath")
|
|
||||||
private Producer captchaProducerMath;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CaptchaProperties captchaProperties;
|
private CaptchaProperties captchaProperties;
|
||||||
|
|
||||||
|
|
@ -54,40 +48,36 @@ public class ValidateCodeServiceImpl implements ValidateCodeService
|
||||||
// 保存验证码信息
|
// 保存验证码信息
|
||||||
String uuid = IdUtils.simpleUUID();
|
String uuid = IdUtils.simpleUUID();
|
||||||
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
|
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
|
||||||
|
|
||||||
String capStr = null, code = null;
|
|
||||||
BufferedImage image = null;
|
|
||||||
|
|
||||||
String captchaType = captchaProperties.getType();
|
|
||||||
// 生成验证码
|
// 生成验证码
|
||||||
if ("math".equals(captchaType))
|
CaptchaType captchaType = captchaProperties.getType();
|
||||||
{
|
boolean isMath = CaptchaType.MATH == captchaType;
|
||||||
String capText = captchaProducerMath.createText();
|
Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
|
||||||
capStr = capText.substring(0, capText.lastIndexOf("@"));
|
CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
|
||||||
code = capText.substring(capText.lastIndexOf("@") + 1);
|
AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
|
||||||
image = captchaProducerMath.createImage(capStr);
|
captcha.setGenerator(codeGenerator);
|
||||||
}
|
captcha.createCode();
|
||||||
else if ("char".equals(captchaType))
|
String code = isMath ? getCodeResult(captcha.getCode()) : captcha.getCode();
|
||||||
{
|
|
||||||
capStr = code = captchaProducer.createText();
|
|
||||||
image = captchaProducer.createImage(capStr);
|
|
||||||
}
|
|
||||||
|
|
||||||
RedisUtils.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
RedisUtils.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
||||||
// 转换流信息写出
|
ajax.put("uuid", uuid);
|
||||||
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
|
ajax.put("img", captcha.getImageBase64());
|
||||||
try
|
return ajax;
|
||||||
{
|
|
||||||
ImageIO.write(image, "jpg", os);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
return AjaxResult.error(e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ajax.put("uuid", uuid);
|
private String getCodeResult(String capStr) {
|
||||||
ajax.put("img", Base64.encode(os.toByteArray()));
|
int numberLength = captchaProperties.getNumberLength();
|
||||||
return ajax;
|
int a = Convert.toInt(StringUtils.substring(capStr, 0, numberLength).trim());
|
||||||
|
char operator = capStr.charAt(numberLength);
|
||||||
|
int b = Convert.toInt(StringUtils.substring(capStr, numberLength + 1, numberLength + 1 + numberLength).trim());
|
||||||
|
switch (operator) {
|
||||||
|
case '*':
|
||||||
|
return Convert.toStr(a * b);
|
||||||
|
case '+':
|
||||||
|
return Convert.toStr(a + b);
|
||||||
|
case '-':
|
||||||
|
return Convert.toStr(a - b);
|
||||||
|
default:
|
||||||
|
return StringUtils.EMPTY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue