天天看點

圖檔驗證碼的實作-kaptcha

【注意】:适用與springboot項目

1.加載jar包。由于groupId的不同,圖檔驗證碼的樣式會有所不同

<!--計算類型的驗證碼 -->
        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>${kaptcha.version}</version>
        </dependency>
           
圖檔驗證碼的實作-kaptcha

//-----------分割線---------------------

<!-- 6位數字的驗證碼-->
<dependency>
    <groupId>com.github.axet</groupId>
    <artifactId>kaptcha</artifactId>
    <version>${kaptcha.version}</version>
</dependency>
           
圖檔驗證碼的實作-kaptcha

2.配置kaptcha,在配置類中配置

  • 計算類型驗證碼的配置類
@Configuration
public class CaptchaConfig
{
    @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.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;
    }
}
           
  • 6位數字的驗證碼的配置類
@Configuration
public class KaptchaConfig {

    @Bean
    public DefaultKaptcha producer() {
        Properties properties = new Properties();
        properties.put("kaptcha.border", "no");
        properties.put("kaptcha.textproducer.font.color", "black");
        properties.put("kaptcha.textproducer.char.space", "5");
        Config config = new Config(properties);
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}
           

3.生成驗證碼并且擷取

  • 圖一的
@Slf4j
@Component
@AllArgsConstructor
public class ImgCodeHandler implements HandlerFunction<ServerResponse>
{
    private final Producer            producer;

    private final StringRedisTemplate redisTemplate;

    @Override
    public Mono<ServerResponse> handle(ServerRequest serverRequest)
    {
        // 生成驗證碼
        String capText = producer.createText();
        String capStr = capText.substring(0, capText.lastIndexOf("@"));
        String code = capText.substring(capText.lastIndexOf("@") + 1);
        BufferedImage image = producer.createImage(capStr);
        // 儲存驗證碼資訊
        String randomStr = UUID.randomUUID().toString().replaceAll("-", "");
        redisTemplate.opsForValue().set(Constants.DEFAULT_CODE_KEY + randomStr, code, 60, TimeUnit.SECONDS);
        // 轉換流資訊寫出
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        try
        {
            ImageIO.write(image, "jpg", os);
        }
        catch (IOException e)
        {
            log.error("ImageIO write err", e);
            return Mono.error(e);
        }
        return ServerResponse.status(HttpStatus.OK).contentType(MediaType.IMAGE_JPEG).header("randomstr", randomStr)
                .body(BodyInserters.fromResource(new ByteArrayResource(os.toByteArray())));
    }
}
           
  • 圖二的
@GetMapping("captcha.jpg")
    public void captcha(HttpServletResponse response) throws ServletException, IOException {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");

        // 生成文字驗證碼
        String text = producer.createText();
        // 生成圖檔驗證碼
        BufferedImage image = producer.createImage(text);
        // 儲存到驗證碼到 session
        ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text);

        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);    
        IOUtils.closeQuietly(out);
    }
           

4.登入接口增加驗證碼驗證

  • 圖一的

    暫無

  • 圖二的
/**
     * 登入接口
     */
    @PostMapping(value = "/login")
    public HttpResult login(@RequestBody LoginBean loginBean) throws IOException {
        String userName = loginBean.getAccount();
        String password = loginBean.getPassword();
        String captcha = loginBean.getCaptcha();
        
        // 從session中擷取之前儲存的驗證碼跟前台傳來的驗證碼進行比對
        Object kaptcha = ShiroUtils.getSessionAttribute(Constants.KAPTCHA_SESSION_KEY);
        if(kaptcha == null){
            return HttpResult.error("驗證碼已失效");
        }
        if(!captcha.equals(kaptcha)){
            return HttpResult.error("驗證碼不正确");
        }
        
        // 使用者資訊
        SysUser user = sysUserService.findByName(userName);

        // 賬号不存在、密碼錯誤
        if (user == null) {
            return HttpResult.error("賬号不存在");
        }
        
        if (!match(user, password)) {
            return HttpResult.error("密碼不正确");
        }

        // 賬号鎖定
        if (user.getStatus() == 0) {
            return HttpResult.error("賬号已被鎖定,請聯系管理者");
        }

        // 生成token,并儲存到資料庫
        SysUserToken data = sysUserTokenService.createToken(user.getId());
        return HttpResult.ok(data);
    }