RuoYi
2020-07-23 df3ef54b41466f34dfda99313fdc9fb7b4de81b3
验证码类型支持(数组计算、字符验证)
已修改5个文件
已添加2个文件
249 ■■■■■ 文件已修改
pom.xml 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/pom.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-ui/src/views/login.vue 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -21,6 +21,7 @@
        <druid.version>1.1.14</druid.version>
        <bitwalker.version>1.19</bitwalker.version>
        <swagger.version>2.9.2</swagger.version>
        <kaptcha.version>2.3.2</kaptcha.version>
        <pagehelper.boot.version>1.2.5</pagehelper.boot.version>
        <fastjson.version>1.2.70</fastjson.version>
        <oshi.version>3.9.1</oshi.version>
@@ -137,6 +138,13 @@
                <artifactId>jjwt</artifactId>
                <version>${jwt.version}</version>
            </dependency>
            <!--验证码 -->
            <dependency>
                <groupId>com.github.penggle</groupId>
                <artifactId>kaptcha</artifactId>
                <version>${kaptcha.version}</version>
            </dependency>
            
            <!-- å®šæ—¶ä»»åŠ¡-->
            <dependency>
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
@@ -1,16 +1,20 @@
package com.ruoyi.web.controller.common;
import java.io.ByteArrayOutputStream;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.code.kaptcha.Producer;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.VerifyCodeUtils;
import com.ruoyi.common.utils.sign.Base64;
import com.ruoyi.common.utils.uuid.IdUtils;
@@ -22,8 +26,18 @@
@RestController
public class CaptchaController
{
    @Resource(name = "captchaProducer")
    private Producer captchaProducer;
    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;
    @Autowired
    private RedisCache redisCache;
    // éªŒè¯ç ç±»åž‹
    @Value("${ruoyi.captchaType}")
    private String captchaType;
    /**
     * ç”ŸæˆéªŒè¯ç 
@@ -31,32 +45,42 @@
    @GetMapping("/captchaImage")
    public AjaxResult getCode(HttpServletResponse response) throws IOException
    {
        // ç”Ÿæˆéšæœºå­—串
        String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
        // å”¯ä¸€æ ‡è¯†
        // ä¿å­˜éªŒè¯ç ä¿¡æ¯
        String uuid = IdUtils.simpleUUID();
        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
        redisCache.setCacheObject(verifyKey, verifyCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        // ç”Ÿæˆå›¾ç‰‡
        int w = 111, h = 36;
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        VerifyCodeUtils.outputImage(w, h, stream, verifyCode);
        String capStr = null, code = null;
        BufferedImage image = null;
        // ç”ŸæˆéªŒè¯ç 
        if ("math".equals(captchaType))
        {
            String capText = captchaProducerMath.createText();
            capStr = capText.substring(0, capText.lastIndexOf("@"));
            code = capText.substring(capText.lastIndexOf("@") + 1);
            image = captchaProducerMath.createImage(capStr);
        }
        else if ("char".equals(captchaType))
        {
            capStr = code = captchaProducer.createText();
            image = captchaProducer.createImage(capStr);
        }
        redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        // è½¬æ¢æµä¿¡æ¯å†™å‡º
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        try
        {
            AjaxResult ajax = AjaxResult.success();
            ajax.put("uuid", uuid);
            ajax.put("img", Base64.encode(stream.toByteArray()));
            return ajax;
            ImageIO.write(image, "jpg", os);
        }
        catch (Exception e)
        catch (IOException e)
        {
            e.printStackTrace();
            return AjaxResult.error(e.getMessage());
        }
        finally
        {
            stream.close();
        }
        AjaxResult ajax = AjaxResult.success();
        ajax.put("uuid", uuid);
        ajax.put("img", Base64.encode(os.toByteArray()));
        return ajax;
    }
}
ruoyi-admin/src/main/resources/application.yml
@@ -12,6 +12,8 @@
  profile: D:/ruoyi/uploadPath
  # èŽ·å–ip地址开关
  addressEnabled: false
  # éªŒè¯ç ç±»åž‹ math æ•°ç»„计算 char å­—符验证
  captchaType: char
# å¼€å‘环境配置
server:
ruoyi-framework/pom.xml
@@ -35,6 +35,18 @@
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <!-- éªŒè¯ç  -->
        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>javax.servlet-api</artifactId>
                    <groupId>javax.servlet</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- èŽ·å–ç³»ç»Ÿä¿¡æ¯ -->
        <dependency>
            <groupId>com.github.oshi</groupId>
ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
package com.ruoyi.framework.config;
import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import static com.google.code.kaptcha.Constants.*;
/**
 * éªŒè¯ç é…ç½®
 *
 * @author ruoyi
 */
@Configuration
public class CaptchaConfig
{
    @Bean(name = "captchaProducer")
    public DefaultKaptcha getKaptchaBean()
    {
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        Properties properties = new Properties();
        // æ˜¯å¦æœ‰è¾¹æ¡† é»˜è®¤ä¸ºtrue æˆ‘们可以自己设置yes,no
        properties.setProperty(KAPTCHA_BORDER, "yes");
        // éªŒè¯ç æ–‡æœ¬å­—符颜色 é»˜è®¤ä¸ºColor.BLACK
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
        // éªŒè¯ç å›¾ç‰‡å®½åº¦ é»˜è®¤ä¸º200
        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
        // éªŒè¯ç å›¾ç‰‡é«˜åº¦ é»˜è®¤ä¸º50
        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
        // éªŒè¯ç æ–‡æœ¬å­—符大小 é»˜è®¤ä¸º40
        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
        // 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();
        Properties properties = new Properties();
        // æ˜¯å¦æœ‰è¾¹æ¡† é»˜è®¤ä¸ºtrue æˆ‘们可以自己设置yes,no
        properties.setProperty(KAPTCHA_BORDER, "yes");
        // è¾¹æ¡†é¢œè‰² é»˜è®¤ä¸ºColor.BLACK
        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
        // éªŒè¯ç æ–‡æœ¬å­—符颜色 é»˜è®¤ä¸ºColor.BLACK
        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.framework.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;
    }
}
ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,75 @@
package com.ruoyi.framework.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();
    }
}
ruoyi-ui/src/views/login.vue
@@ -29,7 +29,7 @@
          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
        </el-input>
        <div class="login-code">
          <img :src="codeUrl" @click="getCode" />
          <img :src="codeUrl" @click="getCode" class="login-code-img"/>
        </div>
      </el-form-item>
      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
@@ -200,4 +200,7 @@
  font-size: 12px;
  letter-spacing: 1px;
}
.login-code-img {
  height: 38px;
}
</style>