图片验证码的实现以及校验验证码

1 篇文章 0 订阅
1 篇文章 0 订阅

关于图片验证码的时候,我们用到地方有很多,我们这次做的图片验证码是我们通过代码生成的图片,然后将其加密为Base64编码。
还是之前的一样,我们要线理一下思路,对于验证码,我们需要怎么做

最开始先导入图片验证码的依赖包

 <!-- 图片验证码依赖 -->
        <dependency>
            <groupId>com.github.penggle</groupId>
            <artifactId>kaptcha</artifactId>
            <version>2.3.2</version>
        </dependency>

1、我们需要设置图片验证码的样式,就是显示给我们看的样式,我们需要自己配置
配置文件内存
captchaParameter.properties

#=========================== project Configuration =========================
project.valid-duration=300000
#=========================== captcha Configuration=========================
#\u8FB9\u6846\u989C\u8272
captcha.border.color=blue
#\u8FB9\u6846\u5BBD\u5EA6
captcha.border.thickness=1
#\u56FE\u7247\u5BBD\u5EA6
captcha.image.width=200
#\u56FE\u7247\u9AD8\u5EA6
captcha.image.height=60
#\u56FE\u7247\u5B9E\u73B0\u7C7B
captcha.producer.impl=com.google.code.kaptcha.impl.DefaultKaptcha
#\u9A8C\u8BC1\u7801\u503C
captcha.textproducer.char.string=3456789ABCEFJKMPQRTUVXY
#\u9A8C\u8BC1\u7801\u957F\u5EA6
captcha.textproducer.char.length=4
#\u6587\u5B57\u95F4\u9694
captcha.textproducer.char.space=18
#\u5B57\u4F53
captcha.textproducer.font.name=Arial,Courier
#\u5B57\u4F53\u5927\u5C0F
captcha.textproducer.font.size=30
#\u5B57\u4F53\u989C\u8272
captcha.textproducer.font.color=black
#\u5E72\u6270\u7EBF\u5B9E\u73B0\u7C7B
captcha.nosie.impl=com.google.code.kaptcha.impl.NoNoise
#\u5E72\u6270\u989C\u8272
captcha.nosie.color=lightGray
#\u56FE\u7247\u6837\u5F0F
captcha.obscurificator.impl=com.google.code.kaptcha.impl.ShadowGimpy
#\u80CC\u666F\u5B9E\u73B0\u7C7B
captcha.background.impl=com.google.code.kaptcha.impl.DefaultBackground
#\u80CC\u666F\u6E10\u53D8\u5F00\u59CB
captcha.background.clear.from=lightGray
#\u80CC\u666F\u6E10\u53D8\u7ED3\u675F
captcha.background.clear.to=white
#\u6587\u5B57\u6E32\u67D3\u5668
captcha.word=com.google.code.kaptcha.text.impl.DefaultWordRenderer
#session key
captcha.session.key=KAPTCHA_SESSION_KEY
#session date
captcha.session.date=KAPTCHA_SESSION_DATE

1.1、创建配置实体类,获取到配置文件中的属性
CaptchaParameterConfig

@Data
@Component
@PropertySource(value = {"classpath:captchaParameter.properties"})
public class CaptchaParameterConfig {

    /**
     * 验证码有效期
     */
    @Value("${project.valid-duration}")
    private Integer validDuration;

    /**
     * 边框颜色
     */
    @Value("${captcha.border.color}")
    private String captchaBorderColor;

    /**
     * 边框宽度
     */
    @Value("${captcha.border.thickness}")
    private String captchaBorderThickness;

    /**
     * 图片宽度
     */
    @Value("${captcha.image.width}")
    private String captchaImageWidth;

    /**
     * 图片高度
     */
    @Value("${captcha.image.height}")
    private String captchaImageHeight;

    /**
     * 图片实现类
     */
    @Value("${captcha.producer.impl}")
    private String captchaProducerImpl;

    /**
     * 验证码值
     */
    @Value("${captcha.textproducer.char.string}")
    private String captchaTextProducerCharString;

    /**
     * 验证码长度
     */
    @Value("${captcha.textproducer.char.length}")
    private String captchaTextProducerCharLength;

    /**
     * 文字间隔
     */
    @Value("${captcha.textproducer.char.space}")
    private String captchaTextProducerCharSpace;

    /**
     * 字体
     */
    @Value("${captcha.textproducer.font.name}")
    private String captchaTextProducerFontName;

    /**
     * 字体大小
     */
    @Value("${captcha.textproducer.font.size}")
    private String captchaTextProducerFontSize;

    /**
     * 字体颜色
     */
    @Value("${captcha.textproducer.font.color}")
    private String captchaTextProducerFontColor;

    /**
     * 干扰线实现类
     */
    @Value("${captcha.nosie.impl}")
    private String captchaNosieImpl;

    /**
     * 干扰颜色
     */
    @Value("${captcha.nosie.color}")
    private String captchaNosieColor;

    /**
     * 图片样式
     */
    @Value("${captcha.obscurificator.impl}")
    private String captchaObscurificatorImpl;

    /**
     * 背景实现类
     */
    @Value("${captcha.background.impl}")
    private String captchaBackgroundImpl;

    /**
     * 背景渐变开始
     */
    @Value("${captcha.background.clear.from}")
    private String captchaBackgroundClearFrom;

    /**
     * 背景渐变结束
     */
    @Value("${captcha.background.clear.to}")
    private String captchaBackgroundClearTo;

    /**
     * 文字渲染器
     */
    @Value("${captcha.word}")
    private String captchaWord;

    /**
     * session key
     */
    @Value("${captcha.session.key}")
    private String captchaSessionKey;

    /**
     * session date
     */
    @Value("${captcha.session.date}")
    private String captchaSessionDate;
}

1.2、配置类

@Configuration
public class CaptchaConfig {

    @Autowired
    private CaptchaParameterConfig parameterConfig;


    @Bean
    public DefaultKaptcha producer() {
        Properties properties = new Properties();

        //边框
        properties.put("kaptcha.border", "no");
        properties.put("kaptcha.border.color", parameterConfig.getCaptchaBorderColor());
        properties.put("kaptcha.border.thickness", parameterConfig.getCaptchaBorderThickness());
        //图片
        properties.put("kaptcha.image.width", parameterConfig.getCaptchaImageWidth());
        properties.put("kaptcha.image.height", parameterConfig.getCaptchaImageHeight());
        //图片实现类
        properties.put("kaptcha.producer.impl", parameterConfig.getCaptchaProducerImpl());

        //文本
        properties.put("kaptcha.textproducer.char.space", parameterConfig.getCaptchaTextProducerCharSpace());
        properties.put("kaptcha.textproducer.char.length", parameterConfig.getCaptchaTextProducerCharLength());
        properties.put("kaptcha.textproducer.char.string", parameterConfig.getCaptchaTextProducerCharString());
        properties.put("kaptcha.textproducer.font.name", parameterConfig.getCaptchaTextProducerFontName());
        properties.put("kaptcha.textproducer.font.size", parameterConfig.getCaptchaTextProducerFontSize());
        properties.put("kaptcha.textproducer.font.color", parameterConfig.getCaptchaTextProducerFontColor());

        //干扰
        properties.put("kaptcha.noise.impl", parameterConfig.getCaptchaNosieImpl());
        properties.put("kaptcha.noise.color", parameterConfig.getCaptchaNosieColor());

        //图片样式
        properties.put("kaptcha.background.impl", parameterConfig.getCaptchaBackgroundImpl());
        //渐变
        properties.put("kaptcha.background.clear.from", parameterConfig.getCaptchaBackgroundClearFrom());
        properties.put("kaptcha.background.clear.to", parameterConfig.getCaptchaBackgroundClearTo());

        //文字渲染器
        properties.put("kaptcha.word", parameterConfig.getCaptchaWord());

        //session
        properties.put("kaptcha.session.key", parameterConfig.getCaptchaSessionKey());
        properties.put("kaptcha.session.date", parameterConfig.getCaptchaSessionDate());

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

        return defaultKaptcha;
    }
}

我们的图片验证码的样式就设置好了,但是我这边看不到,这个只是前段能看到
其实主要是有一个方法我们需要用DefaultKaptcha类的方法, 我们根据我们设置的验证码样式,可以使用它的**createText()方法,就可以获取到一个随机的验证码,然后在将我们获取到的验证码放如createImage()**这个方法中,我们就可以得到一个图片验证码

2、实体类
我用的是JPA直接创建的表

@Data
@Entity
@Table(name = "picture")
@EntityListeners(AuditingEntityListener.class)//时间标签,写了它,CreatedDate才能起作用
public class PictureValidationCodeDO {

  /**
   * 主键
   */
  @Id
  @GenericGenerator(name = "system-uuid",strategy = "uuid")
  @GeneratedValue(strategy = GenerationType.AUTO, generator = "system-uuid")
  @Column(length = 50,name = "id")
  private String id;

  /**
   * 创建时间
   */
  @CreatedDate
  @Column(nullable = false, updatable = false, name = "create_date" ,columnDefinition = "datetime COMMENT '创建时间'")
  private Date createDate;

  /**
   * 验证码
   */
  @Column(name = "code", columnDefinition = "varchar(50) comment '验证码' ")
  private String code;

}

3、Service接口

public interface PictureValidationCodeService {

  /**
   * 生成验证码
   * @return
   */
  PictureValidationVO generate() throws Exception;


  /**
   * 校验验证码
   * @param checkRequest
   */
  void validate(PictureValidationCheckRequest checkRequest) throws Exception;
}

PictureValidationVO 只是我自己创建的另一个实体类,它只是用来接收数据的一个实体类,我们可以用DO直接当做返回对象,个人习惯
在这里插入图片描述
4、ServiceImpl(最重要的一步)
我们传参也一样,我这边也自己写了一个实体类,专门用来传参数
PictureValidationCheckRequest 在这里插入图片描述

@Service
@Slf4j
public class PictureValidationCodeServiceImpl implements PictureValidationCodeService {

  @Autowired
  private DefaultKaptcha defaultKaptcha;

  @Autowired
  private PictureValidationCodeRepository pictureValidationCodeRepository;

  @Autowired
  private CaptchaParameterConfig parameterConfig;

  /**
   * 生成验证码
   * @return
   */
  @Override
  public PictureValidationVO generate() throws Exception {
    log.info("生成图片验证码-service-开始");

    //通过DefaultKaptcha获得随机验证码
    String text = defaultKaptcha.createText();

    //生成图片加密后Base64字符串
    String imgBase64String = getImgBase64String(text);

    //添加验证码,保存到数据库中
    PictureValidationCodeDO pictureValidationCodeDO = savePictureValidationCode(text);

    //构造图片验证码(id,code)
    PictureValidationVO pictureValidationVO = new PictureValidationVO(pictureValidationCodeDO.getId(), imgBase64String);

    log.info("生成图片验证码-service-结束[id:{}]", pictureValidationVO.getId());
    return pictureValidationVO;
  }

  /**
   * 校验验证码
   * @param checkRequest
   */
  @Override
  public void validate(PictureValidationCheckRequest checkRequest) throws Exception {
    log.debug("校验图片验证码-service-开始[checkRequest:{}]", checkRequest);

    //根据id查询验证码
    Optional<PictureValidationCodeDO> validationCodeDO = pictureValidationCodeRepository.findById(checkRequest.getId());

    //判断验证码是否存在
    if (!validationCodeDO.isPresent()){
      log.info("校验验证码失败,验证码不存在[checkRequest:{}]", checkRequest);
      throw new Exception("验证码不存在");
    }

    PictureValidationCodeDO pictureValidationCodeDO = validationCodeDO.get();

    //校验验证码是否过期
    if (System.currentTimeMillis() - pictureValidationCodeDO.getCreateDate().getTime() > parameterConfig.getValidDuration()) {
      log.info("校验验证码失败,验证码已过期[checkRequest:{}]", checkRequest);
      throw new Exception("验证码已过期");
    }

    //判断输入的验证码是否正确
    if(!pictureValidationCodeDO.getCode().equals(checkRequest.getCode())){
      log.info("验证码错误[checkRequest:{}]", checkRequest);
    }

    log.info("校验图片验证码-service-结束");

  }


  /**
   * 添加验证码(保存到数据库中)
   * @param code
   * @return
   */
  private PictureValidationCodeDO savePictureValidationCode(String code){

    PictureValidationCodeDO pictureValidationCodeDO = new PictureValidationCodeDO();
    pictureValidationCodeDO.setCode(code);
    PictureValidationCodeDO save = pictureValidationCodeRepository.save(pictureValidationCodeDO);
    return save;
  }

  /**
   * 生成图片加密后Base64字符串
   *
   * @param code
   * @return Base64字符串
   */
  private String getImgBase64String(String code) throws Exception {

  //将我们生成的随机验证码转换为图片
  //将验证码图片转换成字节流
  BufferedImage image = defaultKaptcha.createImage(code);

  //获取二进制输出流
  ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();

  try {
    ImageIO.write(image, "jpg", jpegOutputStream);
  } catch (IOException e) {
    e.printStackTrace();
    throw new Exception("验证码图片转换成字节流失败");
  }
  //返回Base64字符串
  return Base64.encodeBase64String(jpegOutputStream.toByteArray());
}


}

5、然后就是我们的Controller类

@RestController
@Slf4j
@Api(tags = "图片验证码管理", description = "图片验证码管理")
public class PictureValidationCodeController {

  @Autowired
  private PictureValidationCodeService pictureValidationCodeService;

  /**
   * 生成图片验证码
   * @return
   */
  @ApiOperation("生成图片验证码")
  @GetMapping("/generate")
  public PictureValidationVO generate() throws Exception {
    log.info("生成图片验证码开始" );
    PictureValidationVO pictureValidationVO = pictureValidationCodeService.generate();
    log.info("生成验证码成功");
    return pictureValidationVO;
  }
/**
   * 校验验证码
   * @param checkRequest
   * @throws Exception
   */
  @ApiOperation("校验验证码")
  @PostMapping("/validate")
  public void validate(PictureValidationCheckRequest checkRequest) throws Exception {
    log.info("校验验证码开始");
    pictureValidationCodeService.validate(checkRequest);
    log.info("校验验证码成功");
  }
}

然后我们就可以直接测试一下
在这里插入图片描述
这就生成成功了

校验也是一样的,因为我是直接存到数据库的,所以我们直接去数据库看
在这里插入图片描述
这就考验看到,我们的验证码id,以及他们的值,我们在前端看到的话,就是一个图片,和平时的验证码一样

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值