Commit df3ef54b41466f34dfda99313fdc9fb7b4de81b3

Authored by RuoYi
1 parent 1e40e60d

验证码类型支持(数组计算、字符验证)

... ... @@ -21,6 +21,7 @@
21 21 <druid.version>1.1.14</druid.version>
22 22 <bitwalker.version>1.19</bitwalker.version>
23 23 <swagger.version>2.9.2</swagger.version>
  24 + <kaptcha.version>2.3.2</kaptcha.version>
24 25 <pagehelper.boot.version>1.2.5</pagehelper.boot.version>
25 26 <fastjson.version>1.2.70</fastjson.version>
26 27 <oshi.version>3.9.1</oshi.version>
... ... @@ -137,6 +138,13 @@
137 138 <artifactId>jjwt</artifactId>
138 139 <version>${jwt.version}</version>
139 140 </dependency>
  141 +
  142 + <!--验证码 -->
  143 + <dependency>
  144 + <groupId>com.github.penggle</groupId>
  145 + <artifactId>kaptcha</artifactId>
  146 + <version>${kaptcha.version}</version>
  147 + </dependency>
140 148  
141 149 <!-- 定时任务-->
142 150 <dependency>
... ...
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
1 1 package com.ruoyi.web.controller.common;
2 2  
3   -import java.io.ByteArrayOutputStream;
  3 +import java.awt.image.BufferedImage;
4 4 import java.io.IOException;
5 5 import java.util.concurrent.TimeUnit;
  6 +import javax.annotation.Resource;
  7 +import javax.imageio.ImageIO;
6 8 import javax.servlet.http.HttpServletResponse;
7 9 import org.springframework.beans.factory.annotation.Autowired;
  10 +import org.springframework.beans.factory.annotation.Value;
  11 +import org.springframework.util.FastByteArrayOutputStream;
8 12 import org.springframework.web.bind.annotation.GetMapping;
9 13 import org.springframework.web.bind.annotation.RestController;
  14 +import com.google.code.kaptcha.Producer;
10 15 import com.ruoyi.common.constant.Constants;
11 16 import com.ruoyi.common.core.domain.AjaxResult;
12 17 import com.ruoyi.common.core.redis.RedisCache;
13   -import com.ruoyi.common.utils.VerifyCodeUtils;
14 18 import com.ruoyi.common.utils.sign.Base64;
15 19 import com.ruoyi.common.utils.uuid.IdUtils;
16 20  
... ... @@ -22,8 +26,18 @@ import com.ruoyi.common.utils.uuid.IdUtils;
22 26 @RestController
23 27 public class CaptchaController
24 28 {
  29 + @Resource(name = "captchaProducer")
  30 + private Producer captchaProducer;
  31 +
  32 + @Resource(name = "captchaProducerMath")
  33 + private Producer captchaProducerMath;
  34 +
25 35 @Autowired
26 36 private RedisCache redisCache;
  37 +
  38 + // 验证码类型
  39 + @Value("${ruoyi.captchaType}")
  40 + private String captchaType;
27 41  
28 42 /**
29 43 * 生成验证码
... ... @@ -31,32 +45,42 @@ public class CaptchaController
31 45 @GetMapping("/captchaImage")
32 46 public AjaxResult getCode(HttpServletResponse response) throws IOException
33 47 {
34   - // 生成随机字串
35   - String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
36   - // 唯一标识
  48 + // 保存验证码信息
37 49 String uuid = IdUtils.simpleUUID();
38 50 String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
39 51  
40   - redisCache.setCacheObject(verifyKey, verifyCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
41   - // 生成图片
42   - int w = 111, h = 36;
43   - ByteArrayOutputStream stream = new ByteArrayOutputStream();
44   - VerifyCodeUtils.outputImage(w, h, stream, verifyCode);
45   - try
  52 + String capStr = null, code = null;
  53 + BufferedImage image = null;
  54 +
  55 + // 生成验证码
  56 + if ("math".equals(captchaType))
46 57 {
47   - AjaxResult ajax = AjaxResult.success();
48   - ajax.put("uuid", uuid);
49   - ajax.put("img", Base64.encode(stream.toByteArray()));
50   - return ajax;
  58 + String capText = captchaProducerMath.createText();
  59 + capStr = capText.substring(0, capText.lastIndexOf("@"));
  60 + code = capText.substring(capText.lastIndexOf("@") + 1);
  61 + image = captchaProducerMath.createImage(capStr);
51 62 }
52   - catch (Exception e)
  63 + else if ("char".equals(captchaType))
53 64 {
54   - e.printStackTrace();
55   - return AjaxResult.error(e.getMessage());
  65 + capStr = code = captchaProducer.createText();
  66 + image = captchaProducer.createImage(capStr);
56 67 }
57   - finally
  68 +
  69 + redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
  70 + // 转换流信息写出
  71 + FastByteArrayOutputStream os = new FastByteArrayOutputStream();
  72 + try
58 73 {
59   - stream.close();
  74 + ImageIO.write(image, "jpg", os);
60 75 }
  76 + catch (IOException e)
  77 + {
  78 + return AjaxResult.error(e.getMessage());
  79 + }
  80 +
  81 + AjaxResult ajax = AjaxResult.success();
  82 + ajax.put("uuid", uuid);
  83 + ajax.put("img", Base64.encode(os.toByteArray()));
  84 + return ajax;
61 85 }
62 86 }
... ...
ruoyi-admin/src/main/resources/application.yml
... ... @@ -12,6 +12,8 @@ ruoyi:
12 12 profile: D:/ruoyi/uploadPath
13 13 # 获取ip地址开关
14 14 addressEnabled: false
  15 + # 验证码类型 math 数组计算 char 字符验证
  16 + captchaType: char
15 17  
16 18 # 开发环境配置
17 19 server:
... ...
ruoyi-framework/pom.xml
... ... @@ -35,6 +35,18 @@
35 35 <artifactId>druid-spring-boot-starter</artifactId>
36 36 </dependency>
37 37  
  38 + <!-- 验证码 -->
  39 + <dependency>
  40 + <groupId>com.github.penggle</groupId>
  41 + <artifactId>kaptcha</artifactId>
  42 + <exclusions>
  43 + <exclusion>
  44 + <artifactId>javax.servlet-api</artifactId>
  45 + <groupId>javax.servlet</groupId>
  46 + </exclusion>
  47 + </exclusions>
  48 + </dependency>
  49 +
38 50 <!-- 获取系统信息 -->
39 51 <dependency>
40 52 <groupId>com.github.oshi</groupId>
... ...
ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java 0 → 100644
  1 +package com.ruoyi.framework.config;
  2 +
  3 +import java.util.Properties;
  4 +import org.springframework.context.annotation.Bean;
  5 +import org.springframework.context.annotation.Configuration;
  6 +import com.google.code.kaptcha.impl.DefaultKaptcha;
  7 +import com.google.code.kaptcha.util.Config;
  8 +import static com.google.code.kaptcha.Constants.*;
  9 +
  10 +/**
  11 + * 验证码配置
  12 + *
  13 + * @author ruoyi
  14 + */
  15 +@Configuration
  16 +public class CaptchaConfig
  17 +{
  18 + @Bean(name = "captchaProducer")
  19 + public DefaultKaptcha getKaptchaBean()
  20 + {
  21 + DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
  22 + Properties properties = new Properties();
  23 + // 是否有边框 默认为true 我们可以自己设置yes,no
  24 + properties.setProperty(KAPTCHA_BORDER, "yes");
  25 + // 验证码文本字符颜色 默认为Color.BLACK
  26 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
  27 + // 验证码图片宽度 默认为200
  28 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
  29 + // 验证码图片高度 默认为50
  30 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
  31 + // 验证码文本字符大小 默认为40
  32 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
  33 + // KAPTCHA_SESSION_KEY
  34 + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
  35 + // 验证码文本字符长度 默认为5
  36 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
  37 + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
  38 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
  39 + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
  40 + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
  41 + Config config = new Config(properties);
  42 + defaultKaptcha.setConfig(config);
  43 + return defaultKaptcha;
  44 + }
  45 +
  46 + @Bean(name = "captchaProducerMath")
  47 + public DefaultKaptcha getKaptchaBeanMath()
  48 + {
  49 + DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
  50 + Properties properties = new Properties();
  51 + // 是否有边框 默认为true 我们可以自己设置yes,no
  52 + properties.setProperty(KAPTCHA_BORDER, "yes");
  53 + // 边框颜色 默认为Color.BLACK
  54 + properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
  55 + // 验证码文本字符颜色 默认为Color.BLACK
  56 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
  57 + // 验证码图片宽度 默认为200
  58 + properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
  59 + // 验证码图片高度 默认为50
  60 + properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
  61 + // 验证码文本字符大小 默认为40
  62 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
  63 + // KAPTCHA_SESSION_KEY
  64 + properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
  65 + // 验证码文本生成器
  66 + properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.framework.config.KaptchaTextCreator");
  67 + // 验证码文本字符间距 默认为2
  68 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
  69 + // 验证码文本字符长度 默认为5
  70 + properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
  71 + // 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
  72 + properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
  73 + // 验证码噪点颜色 默认为Color.BLACK
  74 + properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
  75 + // 干扰实现类
  76 + properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
  77 + // 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
  78 + properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
  79 + Config config = new Config(properties);
  80 + defaultKaptcha.setConfig(config);
  81 + return defaultKaptcha;
  82 + }
  83 +}
... ...
ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java 0 → 100644
  1 +package com.ruoyi.framework.config;
  2 +
  3 +import java.util.Random;
  4 +import com.google.code.kaptcha.text.impl.DefaultTextCreator;
  5 +
  6 +/**
  7 + * 验证码文本生成器
  8 + *
  9 + * @author ruoyi
  10 + */
  11 +public class KaptchaTextCreator extends DefaultTextCreator
  12 +{
  13 + private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
  14 +
  15 + @Override
  16 + public String getText()
  17 + {
  18 + Integer result = 0;
  19 + Random random = new Random();
  20 + int x = random.nextInt(10);
  21 + int y = random.nextInt(10);
  22 + StringBuilder suChinese = new StringBuilder();
  23 + int randomoperands = (int) Math.round(Math.random() * 2);
  24 + if (randomoperands == 0)
  25 + {
  26 + result = x * y;
  27 + suChinese.append(CNUMBERS[x]);
  28 + suChinese.append("*");
  29 + suChinese.append(CNUMBERS[y]);
  30 + }
  31 + else if (randomoperands == 1)
  32 + {
  33 + if (!(x == 0) && y % x == 0)
  34 + {
  35 + result = y / x;
  36 + suChinese.append(CNUMBERS[y]);
  37 + suChinese.append("/");
  38 + suChinese.append(CNUMBERS[x]);
  39 + }
  40 + else
  41 + {
  42 + result = x + y;
  43 + suChinese.append(CNUMBERS[x]);
  44 + suChinese.append("+");
  45 + suChinese.append(CNUMBERS[y]);
  46 + }
  47 + }
  48 + else if (randomoperands == 2)
  49 + {
  50 + if (x >= y)
  51 + {
  52 + result = x - y;
  53 + suChinese.append(CNUMBERS[x]);
  54 + suChinese.append("-");
  55 + suChinese.append(CNUMBERS[y]);
  56 + }
  57 + else
  58 + {
  59 + result = y - x;
  60 + suChinese.append(CNUMBERS[y]);
  61 + suChinese.append("-");
  62 + suChinese.append(CNUMBERS[x]);
  63 + }
  64 + }
  65 + else
  66 + {
  67 + result = x + y;
  68 + suChinese.append(CNUMBERS[x]);
  69 + suChinese.append("+");
  70 + suChinese.append(CNUMBERS[y]);
  71 + }
  72 + suChinese.append("=?@" + result);
  73 + return suChinese.toString();
  74 + }
  75 +}
0 76 \ No newline at end of file
... ...
ruoyi-ui/src/views/login.vue
... ... @@ -29,7 +29,7 @@
29 29 <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
30 30 </el-input>
31 31 <div class="login-code">
32   - <img :src="codeUrl" @click="getCode" />
  32 + <img :src="codeUrl" @click="getCode" class="login-code-img"/>
33 33 </div>
34 34 </el-form-item>
35 35 <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
... ... @@ -200,4 +200,7 @@ export default {
200 200 font-size: 12px;
201 201 letter-spacing: 1px;
202 202 }
  203 +.login-code-img {
  204 + height: 38px;
  205 +}
203 206 </style>
... ...