07基于kaptcha生成图片验证码

生成图片验证码

为了保护系统的安全,在进行一些比较重要的操作时都需要输入验证码,因为验证码可以防止恶性攻击如XSS跨站脚本攻击CSRF跨站请求伪造攻击

  • 应用场景: 认证, 找回密码, 人机判断, 支付验证等
  • 验证码类型: 图片、语音、手机短信验证码等

在这里插入图片描述

环境搭建

第一步: 在工程根目录下创建验证码服务工程xuecheng-plus-checkcode为其他微服务的各种业务提供验证码的生成、校验等服务

<!--redis依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--common-pool-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<!--kaptcha-->
<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>

第二步: 由于验证码是缓存在redis中的,所以我们需要部署Redis

docker pull redis
docker run -d --name myredis -p 6379:6379 redis
docker start myredis

第三步: 在Nacos的dev环境下新增checkcode-dev.yamlredis-dev.yaml(group设置为xuecheng-plus-common)

# checkcode-dev.yaml
server:
  servlet:
    context-path: /checkcode
  port: 63075
# redis-dev.yaml
spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
    lettuce:
      pool:
        max-active: 20
        max-idle: 10
        min-idle: 0
    timeout: 10000
    #redisson:
      #配置文件目录
      #config: classpath:singleServerConfig.yaml

第四步: 在本地配置bootstrap.yml文件

spring:
  application:
    name: checkcode
  cloud:
    nacos:
      server-addr: 192.168.101.65:8848
      discovery:
        namespace: dev
        group: xuecheng-plus-project
      config:
        namespace: dev
        group: xuecheng-plus-project
        file-extension: yaml
        refresh-enabled: true
        shared-configs:
          - data-id: swagger-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true
          - data-id: logging-${spring.profiles.active}.yaml
            group: xuecheng-plus-common
            refresh: true
          - data-id: redis-${spring.profiles.active}.yaml # 引入redis的配置
            group: xuecheng-plus-common
            refresh: true
  profiles:
    active: dev

第五步: 在网关工程的的gateway-dev.yaml配置文件新增网关路由到认证服务和验证码服务的配置

spring:
  cloud:
    gateway:
      routes: # 网关路由配置
        - id: auth-service # 路由的目标地址 
          uri: lb://auth-service
          predicates:
            - Path=/auth/**
        - id: checkcode # 路由的目标地址 
          uri: lb://checkcode
          predicates:
            - Path=/checkcode/**

请求响应模型类

请求模型类

@Data
public class CheckCodeParamsDto {
    /**
     * 验证码类型:pic、sms、email等
     */
    private String checkCodeType;
    /**
     * 业务携带参数
     */
    private String param1;
    private String param2;
    private String param3;
}

响应模型类

@Data
public class CheckCodeResultDto {
    // 存储验证码的key
    private String key;
    // 对验证码进行脱敏,图片验证码为base64编码(加密),短信验证码为:null,邮件验证码为: null,邮件链接点击验证为:null
    private String aliasing;
}

生成图片验证码

第一步: 定义api接口并接受请求参数

@Api(value = "验证码服务接口")
@RestController
public class CheckCodeController {
    @Resource(name = "PicCheckCodeService")
    private CheckCodeService picCheckCodeService;
    
    @ApiOperation(value = "生成验证信息", notes = "生成验证信息")
    @PostMapping(value = "/pic")
    public CheckCodeResultDto generatePicCheckCode(CheckCodeParamsDto checkCodeParamsDto) {
        return picCheckCodeService.generate(checkCodeParamsDto);
    }
}

第二步:定义service接口CheckCodeService,定义生成和校验验证码的方法,并定义验证码生成器子接口,key生成器子接口,验证码存储器子接口

  • 设计子接口允许开发者根据需要实现不同的验证码生成策略、key生成策略和验证码存储策略,从而实现高度的模块化和可扩展性
public interface CheckCodeService {
    /**
     * @param checkCodeParamsDto 生成验证码参数
     * @return com.xuecheng.checkcode.model.CheckCodeResultDto 验证码结果
     * @description 生成验证码
     */
    CheckCodeResultDto generate(CheckCodeParamsDto checkCodeParamsDto); 
    
    /**
     * @description 验证码生成器
     */
    public interface CheckCodeGenerator {
        // 验证码
        String generate(int length);
    }
    
    /**
     * @description key生成器
     */
    public interface KeyGenerator {
        // key生成
        String generate(String prefix);
    }
    
    /**
     * @description 验证码存储器
     */
    public interface CheckCodeStore {
        /**
         * @param key    key
         * @param value  value
         * @param expire 过期时间,单位秒
         * @description 向缓存设置key
         */
        void set(String key, String value, Integer expire);
        String get(String key);
        void remove(String key);
    }
}

第三步: 定义CheckCodeGenerator验证码生成器的实现类

@Component("NumberLetterCheckCodeGenerator")
public class NumberLetterCheckCodeGenerator implements CheckCodeService.CheckCodeGenerator {
    @Override
    public String generate(int length) {
        String str="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random=new Random();
        StringBuffer sb=new StringBuffer();
        for(int i=0;i<length;i++){
            // 生成一个范围在0到35之间的随机数,因为str的长度是36
            int number=random.nextInt(36);
            // 使用这个随机数作为索引从str中取出一个字符,并追加到StringBuffer中
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }
}

第四步: 定义KeyGeneratorkey生成器的实现类

@Component("UUIDKeyGenerator")
public class UUIDKeyGenerator implements CheckCodeService.KeyGenerator {
    @Override
    public String generate(String prefix) {
        String uuid = UUID.randomUUID().toString();
        return prefix + uuid.replaceAll("-", "");
    }
}

第五步: 定义CheckCodeStore验证码存储器的实现类,这里是将生成的验证码存储到Redis当中,验证码对应生成的key需要返回给前端,当用户提交验证码的时候需要使用

@Component("MemoryCheckCodeStore")
public class MemoryCheckCodeStore implements CheckCodeService.CheckCodeStore {
    // 注入StringRedisTemplate
    @Autowired
    StringRedisTemplate redisTemplate;

    @Override
    public void set(String key, String value, Integer expire) {
        redisTemplate.opsForValue().set(key, value, expire, TimeUnit.MINUTE);
    }

    @Override
    public String get(String key) {
        return (String) redisTemplate.opsForValue().get(key);
    }

    @Override
    public void remove(String key) {
        redisTemplate.delete(key);
    }
}

// 使用本地内存存储验证码
Map<String,String> map = new HashMap<String,String>();

@Override
public void set(String key, String value, Integer expire) {
    map.put(key,value);
}

@Override
public String get(String key) {
    return map.get(key);
}

@Override
public void remove(String key) {
    map.remove(key);
}

第三步: 定义AbstractCheckCodeService(适配器)实现CheckCodeService的部分方法,定义内部类GenerateResult存储生成的key和code(验证码)

@Slf4j
public abstract class AbstractCheckCodeService implements CheckCodeService {
    // 验证码生成器
    protected CheckCodeGenerator checkCodeGenerator;
    
    // key生成器
    protected KeyGenerator keyGenerator;
    
    // 验证码存储器
    protected CheckCodeStore checkCodeStore;
    
    // 存储key和code
    @Data
    protected class GenerateResult{
        String key;
        String code;
    }
    
    /**
     * @description 生成验证码的公用方法
     * @param checkCodeParamsDto 生成验证码参数
     * @param code_length 验证码长度
     * @param keyPrefix key的前缀
     * @param expire 过期时间
     * @return GenerateResult 生成结果(验证码和对应存储key)
    */
    public GenerateResult generate(CheckCodeParamsDto checkCodeParamsDto,Integer code_length,String keyPrefix,Integer expire){
        // 生成四位验证码
        String code = checkCodeGenerator.generate(code_length);
        log.debug("生成验证码:{}",code);
        // 生成验证码在Redis中存储的key
        String key = keyGenerator.generate(keyPrefix);
        // 将生成的验证码存储到Redis当中
        checkCodeStore.set(key,code,expire);
        // 返回验证码生成结果
        GenerateResult generateResult = new GenerateResult();
        generateResult.setKey(key);
        generateResult.setCode(code);
        return generateResult;
    }
    
    // 等待子类实现核心方法
    public abstract void  setCheckCodeGenerator(CheckCodeGenerator checkCodeGenerator);
    public abstract void  setKeyGenerator(KeyGenerator keyGenerator);
    public abstract void  setCheckCodeStore(CheckCodeStore CheckCodeStore);
    // 生成图片验证码
    public abstract CheckCodeResultDto generate(CheckCodeParamsDto checkCodeParamsDto);
}

定义service接口实现类并继承AbstractCheckCodeService,注入CheckCodeGenerator,KeyGenerator,CheckCodeStore接口的实现类并实现生成图片验证码的业务逻辑

@Service("PicCheckCodeService")
public class PicCheckCodeServiceImpl extends AbstractCheckCodeService implements CheckCodeService {
    // 用于生成Kaptcha验证码的组件
    @Autowired
    private DefaultKaptcha kaptcha;
    
    // 注入CheckCodeGenerator接口的实现类
    @Resource(name="NumberLetterCheckCodeGenerator")
    @Override
    public void setCheckCodeGenerator(CheckCodeGenerator checkCodeGenerator) {
        this.checkCodeGenerator = checkCodeGenerator;
    }
    
    // 注入KeyGenerator接口的实现类
    @Resource(name="UUIDKeyGenerator")
    @Override
    public void setKeyGenerator(KeyGenerator keyGenerator) {
        this.keyGenerator = keyGenerator;
    }
    
    // 注入CheckCodeStore接口的实现类
    @Resource(name="MemoryCheckCodeStore")
    @Override
    public void setCheckCodeStore(CheckCodeStore checkCodeStore) {
        this.checkCodeStore = checkCodeStore;
    }
	
	// 生成图片验证码
    @Override
    public CheckCodeResultDto generate(CheckCodeParamsDto checkCodeParamsDto) {
        // 调用公用的方法生成四位验证码,将验证码缓存到Redis当中并指定key的前缀和有效期
        GenerateResult generate = generate(checkCodeParamsDto, 4, "checkcode:", 60);
        // GenerateResult中存储了生成的验证码的key和值
        String key = generate.getKey();
        String code = generate.getCode();
        // 将生成的验证码使用Base64编码转换为图片(可以在浏览器中直接打开)
        String pic = createPic(code);
        // 将图片的Base64编码存储在CheckCodeResultDto对象中返回
        CheckCodeResultDto checkCodeResultDto = new CheckCodeResultDto();
        checkCodeResultDto.setAliasing(pic);
        checkCodeResultDto.setKey(key);
        return checkCodeResultDto;
    }
	
    // 根据验证码code生成对应的图片
    private String createPic(String code) {
        ByteArrayOutputStream outputStream = null;
        // 使用kaptcha对象生成一个包含验证码值的图片
        BufferedImage image = kaptcha.createImage(code);
        outputStream = new ByteArrayOutputStream();
        String imgBase64Encoder = null;
        try {
            // 将图片转换为字节数组,并对字节数组进行Base64编码
            BASE64Encoder base64Encoder = new BASE64Encoder();
            ImageIO.write(image, "png", outputStream);
            // 返回一个以"data:image/png;base64,"开头的Base64编码的字符串,这个字符串可以直接在HTML中作为图片的源使用,即浏览器可以直接访问
            imgBase64Encoder = "data:image/png;base64," + EncryptUtil.encodeBase64(outputStream.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return imgBase64Encoder;
    }
}

base工程下定义一个工具类:处理网络请求和响应、数据存储以及与外部系统交互时不同格式之间的数据转换

public class EncryptUtil {
    private static final Logger logger = LoggerFactory.getLogger(EncryptUtil.class);
	// 将字节数组转换为Base64编码的字符串
    public static String encodeBase64(byte[] bytes){
        String encoded = Base64.getEncoder().encodeToString(bytes);
        return encoded;
    }
	// 将Base64编码的字符串解码为字节数组
    public static byte[]  decodeBase64(String str){
        byte[] bytes = null;
        bytes = Base64.getDecoder().decode(str);
        return bytes;
    }
	// 将UTF-8编码的字符串转换为Base64编码的字符串
    public static String encodeUTF8StringBase64(String str){
        String encoded = null;
        try {
            encoded = Base64.getEncoder().encodeToString(str.getBytes("utf-8"));
        } catch (UnsupportedEncodingException e) {
            logger.warn("不支持的编码格式",e);
        }
        return encoded;

    }
	// 将Base64编码的字符串解码为UTF-8编码的字符串
    public static String  decodeUTF8StringBase64(String str){
        String decoded = null;
        byte[] bytes = Base64.getDecoder().decode(str);
        try {
            decoded = new String(bytes,"utf-8");
        }catch(UnsupportedEncodingException e){
            logger.warn("不支持的编码格式",e);
        }
        return decoded;
    }
	// 对URL进行编码,以便在URL中安全地传输特殊字符
    public static String encodeURL(String url) {
    	String encoded = null;
		try {
			encoded =  URLEncoder.encode(url, "utf-8");
		} catch (UnsupportedEncodingException e) {
			logger.warn("URLEncode失败", e);
		}
		return encoded;
	}
	// 对编码后的URL进行解码,以还原原始URL
	public static String decodeURL(String url) {
    	String decoded = null;
		try {
			decoded = URLDecoder.decode(url, "utf-8");
		} catch (UnsupportedEncodingException e) {
			logger.warn("URLDecode失败", e);
		}
		return decoded;
	}
	// 测试
    public static void main(String [] args){
        String str = "abcd{'a':'b'}";
        String encoded = EncryptUtil.encodeUTF8StringBase64(str);
        String decoded = EncryptUtil.decodeUTF8StringBase64(encoded);
        System.out.println(str);
        System.out.println(encoded);
        System.out.println(decoded);

        String url = "== wo";
        String urlEncoded = EncryptUtil.encodeURL(url);
        String urlDecoded = EncryptUtil.decodeURL(urlEncoded);
        
        System.out.println(url);
        System.out.println(urlEncoded);
        System.out.println(urlDecoded);
    }
}

测试生成验证码

第一步: 使用HttpClient访问CheckCodeController中生成验证码图片的接口,响应的图片以base64编码格式存储,同时在Redis中也可以看到我们缓存的验证码
在这里插入图片描述

// 获取验证码图片
POST localhost:63075/checkcode/pic


{
 // 生成的验证码存储在Redis中对应的key
 "key": "checkcode:20a2ccb511bc472ea785db14d0a547ba",
 /*响应的图片是以base64编码格式存储的,我们可以直接在浏览器中访问*/ "aliasing":"data:image/png;base64,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"

}

校验验证码

校验用户提交的验证码

第一步:定义接口

@Api(value = "验证码服务接口")
@RestController
public class CheckCodeController {
    @Resource(name = "PicCheckCodeService")
    private CheckCodeService picCheckCodeService;

    @ApiOperation(value = "校验", notes = "校验")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "name", value = "业务名称", required = true, dataType = "String", paramType = "query"),
        @ApiImplicitParam(name = "key", value = "验证key", required = true, dataType = "String", paramType = "query"),
        @ApiImplicitParam(name = "code", value = "验证码", required = true, dataType = "String", paramType = "query")
    })
    @PostMapping(value = "/verify")
    public Boolean verify(String key, String code) {
        Boolean isSuccess = picCheckCodeService.verify(key, code);
        return isSuccess;
    }
}
public interface CheckCodeService {
     /**
     * @param key
     * @param code
     * @description 校验验证码
     */
    public boolean verify(String key, String code);   
}

第二步: 在AbstractCheckCodeService抽象类中实现校验验证码的业务逻辑

@Slf4j
public abstract class AbstractCheckCodeService implements CheckCodeService {
    
    /**
     * 校验验证码
     * @param key 提交的验证码key
     * @param code 提交的验证码
     * @return
     */
    public boolean verify(String key, String code){
        if (StringUtils.isBlank(key) || StringUtils.isBlank(code)){
            return false;
        }
        // 根据key从Redis缓存中取出正确的验证码和用户输入的验证码进行比对,如果相同则校验通过,否则不通过
        String code_l = checkCodeStore.get(key);
        if (code_l == null){
            return false;
        }
        // 比较缓存的code_l和传入的code是否相等 
        boolean result = code_l.equalsIgnoreCase(code);
        if(result){
            // 删除缓存的验证码
            checkCodeStore.remove(key);
        }
        return result;
    }
}

测试校验验证码

使用HttpClient访问CheckCodeController中校验验证码的接口,请求时携带生成验证码时返回的key图片中的验证码

POST localhost:63075/checkcode/verisfy?key=checkcode:c3dce1413f95414e943dcf0a97983fe8&code=ZEUY
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值