SpringBoot--图片验证码kaptcha

Love The Way You Lie 2024-05-24 01:46 172阅读 0赞

本文介绍如何在SpringBoot中整合kaptcha,以及如何配置kaptcha,生成验证码和校验等

文章目录

  • 前言
  • 环境搭建
    • 项目结构
    • 添加依赖
  • 代码实现
    • KaptchaConfig
    • Knife4jConfig
    • domain
    • Service
    • util
    • controller
  • 测试
    • 生成验证码
    • 校验验证码

前言

参考链接:

  • Github链接
  • 链接1

Kaptcha 是一个Google开源,可自由配置的图片验证码生成工具,功能十分强大。使用Kaptcha时可以配置图片的宽高、字符内容、干扰类型等,自定义样式。

环境搭建

完整项目,参考https://github.com/miaoyang/spring-learn.git ,该项目还包括其他一些中间件的使用,比如Redis,MongoDB,Swagger等。

项目结构

在这里插入图片描述
将验证码单独写成了一个微服务,在实际开发中,单体项目可以裁剪部分。

添加依赖

pom文件中引入必要的依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>spring-learn</artifactId>
  7. <groupId>org.ym</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>learn-checkcode</artifactId>
  12. <properties>
  13. <maven.compiler.source>8</maven.compiler.source>
  14. <maven.compiler.target>8</maven.compiler.target>
  15. </properties>
  16. <dependencies>
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-starter-web</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework.boot</groupId>
  23. <artifactId>spring-boot-starter-validation</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter</artifactId>
  28. <exclusions>
  29. <exclusion>
  30. <groupId>org.springframework.boot</groupId>
  31. <artifactId>spring-boot-starter-logging</artifactId>
  32. </exclusion>
  33. </exclusions>
  34. </dependency>
  35. <!-- log4j2 -->
  36. <dependency>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-starter-log4j2</artifactId>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.projectlombok</groupId>
  42. <artifactId>lombok</artifactId>
  43. </dependency>
  44. <!--check code-->
  45. <dependency>
  46. <groupId>com.github.penggle</groupId>
  47. <artifactId>kaptcha</artifactId>
  48. <version>2.3.2</version>
  49. </dependency>
  50. <dependency>
  51. <groupId>org.ym</groupId>
  52. <artifactId>learn-common-core</artifactId>
  53. <version>1.0-SNAPSHOT</version>
  54. <scope>compile</scope>
  55. </dependency>
  56. <dependency>
  57. <groupId>org.ym</groupId>
  58. <artifactId>learn-common-swagger</artifactId>
  59. <version>1.0-SNAPSHOT</version>
  60. </dependency>
  61. <dependency>
  62. <groupId>org.ym</groupId>
  63. <artifactId>learn-common-redis</artifactId>
  64. <version>1.0-SNAPSHOT</version>
  65. <scope>compile</scope>
  66. </dependency>
  67. </dependencies>
  68. </project>

application.yml配置

  1. server:
  2. port: 9205
  3. spring:
  4. application:
  5. name: learn-checkcode
  6. mvc:
  7. pathmatch:
  8. matching-strategy: ant_path_matcher
  9. redis:
  10. host: localhost # Redis服务器地址
  11. database: 0 # Redis数据库索引(默认为0)
  12. port: 6379 # Redis服务器连接端口
  13. password: # Redis服务器连接密码(默认为空)
  14. timeout: 3000ms # 连接超时时间(毫秒)
  15. checkcode:
  16. length: 4
  17. prefix-key: check_code_
  18. expire-time: 300 # 300s

代码实现

KaptchaConfig

CheckCodeProperties配置了验证码的一些基本属性,在application.yml 可以修改。

  1. package com.ym.learn.checkcode.config;
  2. import lombok.Data;
  3. import lombok.Getter;
  4. import org.springframework.boot.context.properties.ConfigurationProperties;
  5. import org.springframework.context.annotation.Configuration;
  6. /**
  7. * @Author: Yangmiao
  8. * @Date: 2023/4/21 19:44
  9. * @Desc:
  10. */
  11. @Data
  12. @Configuration
  13. @ConfigurationProperties(prefix = "checkcode")
  14. public class CheckCodeProperties {
  15. /**
  16. * 验证码长度
  17. */
  18. private Integer length;
  19. /**
  20. * key前缀
  21. */
  22. private String prefixKey;
  23. /**
  24. * 缓存过期时间
  25. */
  26. private Integer expireTime;
  27. }
  28. package com.ym.learn.checkcode.config;
  29. import com.google.code.kaptcha.impl.DefaultKaptcha;
  30. import com.google.code.kaptcha.util.Config;
  31. import org.springframework.context.annotation.Bean;
  32. import org.springframework.context.annotation.Configuration;
  33. import java.util.Properties;
  34. /**
  35. * @Author: Yangmiao
  36. * @Date: 2023/4/21 16:25
  37. * @Desc: 验证码配置
  38. */
  39. @Configuration
  40. public class KaptchaConfig {
  41. @Bean
  42. public DefaultKaptcha defaultKaptcha() {
  43. Properties properties = new Properties();
  44. properties.put("kaptcha.border", "no");
  45. // 文本宽度和长度
  46. properties.put("kaptcha.textproducer.char.space", "10");
  47. properties.put("kaptcha.textproducer.char.length","4");
  48. // 宽度和高度
  49. properties.put("kaptcha.image.height","34");
  50. properties.put("kaptcha.image.width","130");
  51. // 字体大小和颜色
  52. properties.put("kaptcha.textproducer.font.size","25");
  53. properties.put("kaptcha.textproducer.font.color", "black");
  54. // 背景
  55. properties.setProperty("kaptcha.background.clear.from", "white");
  56. properties.setProperty("kaptcha.background.clear.to", "white");
  57. properties.put("kaptcha.noise.impl","com.google.code.kaptcha.impl.NoNoise");
  58. Config config = new Config(properties);
  59. DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
  60. defaultKaptcha.setConfig(config);
  61. return defaultKaptcha;
  62. }
  63. }

Knife4jConfig

接口文档配置,该部分参考SpringBoot整合Knife4j,在本文章中,可有可无,不过为了方便测试接口。

  1. package com.ym.learn.checkcode.config;
  2. import com.ym.learn.swagger.config.BaseKnife4jConfig;
  3. import com.ym.learn.swagger.domain.Knife4jProperties;
  4. import org.springframework.context.annotation.Configuration;
  5. import springfox.documentation.oas.annotations.EnableOpenApi;
  6. /**
  7. * @Author: Yangmiao
  8. * @Date: 2023/4/21 22:07
  9. * @Desc:
  10. */
  11. @Configuration
  12. @EnableOpenApi
  13. public class Knife4jConfig extends BaseKnife4jConfig {
  14. @Override
  15. public Knife4jProperties knife4jProperties() {
  16. return Knife4jProperties.builder()
  17. .apiBasePackage("com.ym.learn.checkcode")
  18. .title("验证码服务接口文档")
  19. .description("验证码服务接口文档")
  20. .contactName("ym")
  21. .version("1.0")
  22. .enableSecurity(false)
  23. .build();
  24. }
  25. }

domain

  1. package com.ym.learn.checkcode.domain;
  2. import lombok.Builder;
  3. import lombok.Data;
  4. import lombok.ToString;
  5. /**
  6. * @Author: Yangmiao
  7. * @Date: 2023/4/21 17:36
  8. * @Desc: 返回给客户端的Code
  9. */
  10. @Data
  11. @ToString
  12. @Builder
  13. public class CodeVo {
  14. /**
  15. * 用于验证的key
  16. */
  17. private String key;
  18. /**
  19. * 校验码
  20. */
  21. private String aliasing;
  22. }

Service

  1. package com.ym.learn.checkcode.service;
  2. import com.ym.learn.checkcode.domain.CodeVo;
  3. /**
  4. * @Author: Yangmiao
  5. * @Date: 2023/4/21 17:32
  6. * @Desc:
  7. */
  8. public interface CheckCodeService {
  9. /**
  10. * 校验验证码
  11. * @param key
  12. * @param code
  13. * @return
  14. */
  15. boolean verifyCode(String key, String code);
  16. /**
  17. * 生成验证码
  18. * @param length
  19. * @return
  20. */
  21. CodeVo generateCode(Integer length, String prefixKey,Integer expireTime);
  22. }
  23. package com.ym.learn.checkcode.service.impl;
  24. import cn.hutool.core.io.IoUtil;
  25. import cn.hutool.core.util.StrUtil;
  26. import com.google.code.kaptcha.impl.DefaultKaptcha;
  27. import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
  28. import com.ym.learn.checkcode.domain.CodeVo;
  29. import com.ym.learn.checkcode.service.CheckCodeService;
  30. import com.ym.learn.checkcode.util.CodeUtil;
  31. import com.ym.learn.core.utils.SignUtil;
  32. import com.ym.learn.redis.service.RedisService;
  33. import lombok.extern.slf4j.Slf4j;
  34. import org.springframework.beans.factory.annotation.Autowired;
  35. import org.springframework.stereotype.Service;
  36. import org.springframework.util.StringUtils;
  37. import javax.imageio.ImageIO;
  38. import java.awt.image.BufferedImage;
  39. import java.io.IOException;
  40. /**
  41. * @Author: Yangmiao
  42. * @Date: 2023/4/21 17:33
  43. * @Desc:
  44. */
  45. @Service
  46. @Slf4j
  47. public class CheckCodeServiceImpl implements CheckCodeService {
  48. @Autowired
  49. private DefaultKaptcha defaultKaptcha;
  50. @Autowired
  51. private RedisService redisService;
  52. @Override
  53. public boolean verifyCode(String key, String code) {
  54. if (StrUtil.isEmpty(key) || StrUtil.isEmpty(code)){
  55. return false;
  56. }
  57. String localCode = (String)redisService.get(key);
  58. if (StrUtil.isEmpty(localCode)){
  59. return false;
  60. }
  61. if (!code.equalsIgnoreCase(localCode)){
  62. return false;
  63. }
  64. // 删除缓存
  65. redisService.del(key);
  66. return true;
  67. }
  68. @Override
  69. public CodeVo generateCode(Integer length, String prefixKey, Integer expireTime) {
  70. String code = CodeUtil.generateCode(length);
  71. String key = CodeUtil.generateKey(prefixKey);
  72. // 缓存redis
  73. redisService.set(key,code,expireTime);
  74. // 获取base64编码后的img
  75. String codeImg = generateCodeImg(code);
  76. return CodeVo.builder()
  77. .key(key)
  78. .aliasing(codeImg)
  79. .build();
  80. }
  81. /**
  82. * 生成codeImage
  83. * @param code
  84. * @return
  85. */
  86. private String generateCodeImg(String code){
  87. BufferedImage bufferedImage = defaultKaptcha.createImage(code);
  88. ByteOutputStream byteOutputStream = null;
  89. String codeImg = "";
  90. try {
  91. byteOutputStream = new ByteOutputStream();
  92. ImageIO.write(bufferedImage,"png",byteOutputStream);
  93. codeImg = "data:image/png;base64,"+SignUtil.encodeBase64(byteOutputStream.getBytes());
  94. } catch (IOException e) {
  95. e.printStackTrace();
  96. }finally {
  97. if (byteOutputStream != null) {
  98. byteOutputStream.close();
  99. }
  100. }
  101. return codeImg;
  102. }
  103. }

util

用于生成Key和Code

  1. package com.ym.learn.checkcode.util;
  2. import java.util.Random;
  3. import java.util.UUID;
  4. /**
  5. * @Author: Yangmiao
  6. * @Date: 2023/4/21 17:05
  7. * @Desc: 验证码工具类
  8. */
  9. public class CodeUtil {
  10. /**
  11. * Code字符的取值范围
  12. */
  13. public static final String CODE_NUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  14. /**
  15. * 生成UUID,包括前缀
  16. * @param prefix
  17. * @return
  18. */
  19. public static String generateKey(String prefix){
  20. String uuid = UUID.randomUUID().toString().replaceAll("-", "");
  21. return prefix+uuid;
  22. }
  23. /**
  24. * 生成指定长度的code
  25. * @param len 不指定时,默认为4
  26. * @return
  27. */
  28. public static String generateCode(Integer len){
  29. if (len <= 0){
  30. len = 4;
  31. }
  32. StringBuilder sb = new StringBuilder();
  33. for (int i = 0; i < len; i++) {
  34. Random random = new Random();
  35. int nextInt = random.nextInt(CODE_NUM.length());
  36. sb.append(CODE_NUM.charAt(nextInt));
  37. }
  38. return sb.toString();
  39. }
  40. }

controller

  1. package com.ym.learn.checkcode.controller;
  2. import com.ym.learn.checkcode.config.CheckCodeProperties;
  3. import com.ym.learn.checkcode.domain.CodeVo;
  4. import com.ym.learn.checkcode.service.CheckCodeService;
  5. import com.ym.learn.core.api.R;
  6. import io.swagger.annotations.Api;
  7. import io.swagger.annotations.ApiOperation;
  8. import io.swagger.annotations.ApiParam;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.web.bind.annotation.*;
  11. /**
  12. * @Author: Yangmiao
  13. * @Date: 2023/4/21 17:29
  14. * @Desc: 验证码接口
  15. */
  16. @Api(tags = "验证码接口")
  17. @RestController
  18. @RequestMapping("/checkcode")
  19. public class CheckCodeController {
  20. @Autowired
  21. private CheckCodeService checkCodeService;
  22. @Autowired
  23. private CheckCodeProperties codeProperties;
  24. @ApiOperation(value = "获取验证码")
  25. @GetMapping("/getCheckCode")
  26. public R getCheckCode(){
  27. CodeVo codeVo = checkCodeService.generateCode(codeProperties.getLength(), codeProperties.getPrefixKey(), codeProperties.getExpireTime());
  28. return R.ok(codeVo);
  29. }
  30. @ApiOperation(value = "校验验证码")
  31. @PostMapping("/verifyCheckCode")
  32. public R verifyCheckCode(@ApiParam(name = "key")@RequestParam("key")String key,
  33. @ApiParam(name = "code")@RequestParam("code")String code){
  34. boolean ret = checkCodeService.verifyCode(key, code);
  35. return R.ok(ret);
  36. }
  37. }

测试

使用Knfie4j测试接口
在这里插入图片描述

生成验证码

在这里插入图片描述
aliasing 对应的value复制到浏览器地址,解析出图片如下:
在这里插入图片描述

校验验证码

客户端需要传入key 和验证码数字,服务端从缓存中取出key对应的value值,和客户端传入的验证码进行匹配。
注意:

  • 缓存的时间

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,172人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Kaptcha生成图片验证

    Kaptcha简介 kaptcha 是一个很有用的验证码生成工具。由于它是可配置的,有了它,你能够生成各种样式的验证码。 Kaptcha 是一个可高度配置的实用验证码