SpringBoot: código de verificación de imagen kaptcha

Este artículo presenta cómo integrar kaptcha en SpringBoot y cómo configurar kaptcha, generar código de verificación y verificación, etc.

prefacio

Link de referencia:

Kaptcha es una herramienta de generación de códigos de verificación de imágenes de código abierto, libremente configurable y de código abierto de Google con funciones muy potentes. Al usar Kaptcha, puede configurar el ancho y alto de la imagen, el contenido de los caracteres, el tipo de interferencia, etc., y personalizar el estilo.

Construcción del entorno

Proyecto completo, referencia https://github.com/miaoyang/spring-learn.git, este proyecto también incluye el uso de algún otro middleware, como Redis, MongoDB, Swagger, etc.

estructura del proyecto

inserte la descripción de la imagen aquí
El código de verificación se escribe como un microservicio por separado. En el desarrollo real, un solo proyecto puede cortar partes.

agregar dependencias

Introduce las dependencias necesarias en el archivo pom.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-learn</artifactId>
        <groupId>org.ym</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>learn-checkcode</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- log4j2 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--check code-->
        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.ym</groupId>
            <artifactId>learn-common-core</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

        <dependency>
            <groupId>org.ym</groupId>
            <artifactId>learn-common-swagger</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.ym</groupId>
            <artifactId>learn-common-redis</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

</project>

configuración de aplicación.yml

server:
  port: 9205
spring:
  application:
    name: learn-checkcode
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
  redis:
    host: localhost # Redis服务器地址
    database: 0 # Redis数据库索引(默认为0)
    port: 6379 # Redis服务器连接端口
    password:  # Redis服务器连接密码(默认为空)
    timeout: 3000ms # 连接超时时间(毫秒)

checkcode:
  length: 4
  prefix-key: check_code_
  expire-time: 300 # 300s

Código

KaptchaConfig

CheckCodePropertiesSe configuran algunas propiedades básicas del código de verificación, las cuales application.ymlse pueden modificar en .

package com.ym.learn.checkcode.config;

import lombok.Data;
import lombok.Getter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 19:44
 * @Desc:
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "checkcode")
public class CheckCodeProperties {
    
    
    /**
     * 验证码长度
     */
    private Integer length;
    /**
     * key前缀
     */
    private String prefixKey;
    /**
     * 缓存过期时间
     */
    private Integer expireTime;

}

package com.ym.learn.checkcode.config;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Properties;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 16:25
 * @Desc: 验证码配置
 */
@Configuration
public class KaptchaConfig {
    
    
    @Bean
    public DefaultKaptcha defaultKaptcha() {
    
    
        Properties properties = new Properties();
        properties.put("kaptcha.border", "no");

        // 文本宽度和长度
        properties.put("kaptcha.textproducer.char.space", "10");
        properties.put("kaptcha.textproducer.char.length","4");
        // 宽度和高度
        properties.put("kaptcha.image.height","34");
        properties.put("kaptcha.image.width","130");
        // 字体大小和颜色
        properties.put("kaptcha.textproducer.font.size","25");
        properties.put("kaptcha.textproducer.font.color", "black");
        // 背景
        properties.setProperty("kaptcha.background.clear.from", "white");
        properties.setProperty("kaptcha.background.clear.to", "white");

        properties.put("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");

        Config config = new Config(properties);
        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
        defaultKaptcha.setConfig(config);
        return defaultKaptcha;
    }
}

Cuchillo4jConfig

Configuración del documento de interfaz, esta parte se refiere a SpringBoot que integra Knife4j . En este artículo, es opcional, pero para facilitar la prueba de la interfaz.

package com.ym.learn.checkcode.config;

import com.ym.learn.swagger.config.BaseKnife4jConfig;
import com.ym.learn.swagger.domain.Knife4jProperties;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.oas.annotations.EnableOpenApi;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 22:07
 * @Desc:
 */
@Configuration
@EnableOpenApi
public class Knife4jConfig extends BaseKnife4jConfig {
    
    
    @Override
    public Knife4jProperties knife4jProperties() {
    
    
        return Knife4jProperties.builder()
                .apiBasePackage("com.ym.learn.checkcode")
                .title("验证码服务接口文档")
                .description("验证码服务接口文档")
                .contactName("ym")
                .version("1.0")
                .enableSecurity(false)
                .build();
    }
}

dominio

package com.ym.learn.checkcode.domain;

import lombok.Builder;
import lombok.Data;
import lombok.ToString;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 17:36
 * @Desc: 返回给客户端的Code
 */
@Data
@ToString
@Builder
public class CodeVo {
    
    
    /**
     * 用于验证的key
     */
    private String key;
    /**
     * 校验码
     */
    private String aliasing;
}

Servicio

package com.ym.learn.checkcode.service;

import com.ym.learn.checkcode.domain.CodeVo;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 17:32
 * @Desc:
 */
public interface CheckCodeService {
    
    

    /**
     * 校验验证码
     * @param key
     * @param code
     * @return
     */
    boolean verifyCode(String key, String code);

    /**
     * 生成验证码
     * @param length
     * @return
     */
    CodeVo generateCode(Integer length, String prefixKey,Integer expireTime);
}

package com.ym.learn.checkcode.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
import com.ym.learn.checkcode.domain.CodeVo;
import com.ym.learn.checkcode.service.CheckCodeService;
import com.ym.learn.checkcode.util.CodeUtil;
import com.ym.learn.core.utils.SignUtil;
import com.ym.learn.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 17:33
 * @Desc:
 */
@Service
@Slf4j
public class CheckCodeServiceImpl implements CheckCodeService {
    
    
    @Autowired
    private DefaultKaptcha defaultKaptcha;

    @Autowired
    private RedisService redisService;

    @Override
    public boolean verifyCode(String key, String code) {
    
    
        if (StrUtil.isEmpty(key) || StrUtil.isEmpty(code)){
    
    
            return false;
        }
        String localCode = (String)redisService.get(key);
        if (StrUtil.isEmpty(localCode)){
    
    
            return false;
        }
        if (!code.equalsIgnoreCase(localCode)){
    
    
            return false;
        }
        // 删除缓存
        redisService.del(key);
        return true;
    }

    @Override
    public CodeVo generateCode(Integer length, String prefixKey, Integer expireTime) {
    
    
        String code = CodeUtil.generateCode(length);
        String key = CodeUtil.generateKey(prefixKey);
        // 缓存redis
        redisService.set(key,code,expireTime);
        // 获取base64编码后的img
        String codeImg = generateCodeImg(code);
        return CodeVo.builder()
                .key(key)
                .aliasing(codeImg)
                .build();
    }

    /**
     * 生成codeImage
     * @param code
     * @return
     */
    private String generateCodeImg(String code){
    
    
        BufferedImage bufferedImage = defaultKaptcha.createImage(code);
        ByteOutputStream byteOutputStream = null;
        String codeImg = "";
        try {
    
    
            byteOutputStream = new ByteOutputStream();
            ImageIO.write(bufferedImage,"png",byteOutputStream);
            codeImg = "data:image/png;base64,"+SignUtil.encodeBase64(byteOutputStream.getBytes());
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }finally {
    
    
            if (byteOutputStream != null) {
    
    
                byteOutputStream.close();
            }
        }
        return codeImg;
    }
}

útil

Se utiliza para generar clave y código.

package com.ym.learn.checkcode.util;

import java.util.Random;
import java.util.UUID;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 17:05
 * @Desc: 验证码工具类
 */
public class CodeUtil {
    
    
    /**
     * Code字符的取值范围
     */
    public static final String CODE_NUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    /**
     * 生成UUID,包括前缀
     * @param prefix
     * @return
     */
    public static String generateKey(String prefix){
    
    
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        return prefix+uuid;
    }

    /**
     * 生成指定长度的code
     * @param len 不指定时,默认为4
     * @return
     */
    public static String generateCode(Integer len){
    
    
        if (len <= 0){
    
    
            len = 4;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < len; i++) {
    
    
            Random random = new Random();
            int nextInt = random.nextInt(CODE_NUM.length());
            sb.append(CODE_NUM.charAt(nextInt));
        }
        return sb.toString();
    }

}

controlador

package com.ym.learn.checkcode.controller;

import com.ym.learn.checkcode.config.CheckCodeProperties;
import com.ym.learn.checkcode.domain.CodeVo;
import com.ym.learn.checkcode.service.CheckCodeService;
import com.ym.learn.core.api.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @Author: Yangmiao
 * @Date: 2023/4/21 17:29
 * @Desc: 验证码接口
 */
@Api(tags = "验证码接口")
@RestController
@RequestMapping("/checkcode")
public class CheckCodeController {
    
    

    @Autowired
    private CheckCodeService checkCodeService;

    @Autowired
    private CheckCodeProperties codeProperties;

    @ApiOperation(value = "获取验证码")
    @GetMapping("/getCheckCode")
    public R getCheckCode(){
    
    
        CodeVo codeVo = checkCodeService.generateCode(codeProperties.getLength(), codeProperties.getPrefixKey(), codeProperties.getExpireTime());
        return R.ok(codeVo);
    }

    @ApiOperation(value = "校验验证码")
    @PostMapping("/verifyCheckCode")
    public R verifyCheckCode(@ApiParam(name = "key")@RequestParam("key")String key,
                             @ApiParam(name = "code")@RequestParam("code")String code){
    
    
        boolean ret = checkCodeService.verifyCode(key, code);
        return R.ok(ret);
    }

}

prueba

Utilice Knfie4j para probar la interfaz
inserte la descripción de la imagen aquí

generar código de verificación

inserte la descripción de la imagen aquí
Copie aliasingel valor correspondiente a la dirección del navegador y analice la imagen de la siguiente manera:
inserte la descripción de la imagen aquí

Verificar código de verificación

El cliente debe pasar la clave y el número del código de verificación, y el servidor recupera el valor correspondiente a la clave del caché y lo compara con el código de verificación ingresado por el cliente.
Aviso:

  • Tiempo de Cache

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/baidu_33256174/article/details/130332239
Recomendado
Clasificación