前后端分离实现验证码

前后端分离实现验证码

实现流程

1、前端登录页面加载时发送请求来请求验证码接口

2、服务器端接收到用户验证码的请求之后,使用工具类来生成验证码(base64)

3、将获取到的 验证码 对应的code 保存到 redis 中并设置该码的有效时间,一般建议使用 UUID 作为key,code 做value 来进行保存。直接将 验证码对应的 base64码 和 对应的UUID 响应给前端

4、前端输入完毕之后,发送登录请求时,将接收到的 UUID 作为参数一起携带到服务器端。

5、服务器端接收端到用户请求之后,根据携带来的UUID 从redis中取出对应的数据,再根据用户输入的code来进行判断是否相对即可

实现步骤:redis这里就不做说明了,直接使用springboot的 jedis 即可

1、引入hutool的验证码依赖

<!-- hutool -->
 <dependency>
     <groupId>cn.hutool</groupId>
     <artifactId>hutool-all</artifactId>
     <version>5.5.7</version>
 </dependency>

2、自定义一个用来保存 验证码 信息的 实体类

package com.sany.crane.oa.core.entity;

import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ImgResult {
  @ApiModelProperty("该验证码对应的UUID")
  private String imgUUID;
  @ApiModelProperty("该验证码对应的base64加密格式")
  private String img;
  @ApiModelProperty("该验证码对应的具体码")
  private String code;
}

3、对应的 验证码 生成工具类

package com.sany.crane.oa.common.util;

import cn.hutool.core.codec.Base64;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Random;

@Slf4j
@Data
public class CaptchaUtil {
  //验证码个数
  private int count = 4;
  //验证码宽度,且设置每个字的宽度
  private int width = count * 50;
  //验证码高度
  private int height = 50;
  //图片验证码key
  private String code = "";
  //bufferedImage
  private BufferedImage bufferedImage;

  //测试写入
  public static void main(String[] args) {
    long startend = System.currentTimeMillis();
    CaptchaUtil captchaUtil = new CaptchaUtil();
    //默认验证码位数为4,我这里设为5
    captchaUtil.setCount(5);
    //得到缓冲区
    BufferedImage image = captchaUtil.getImage();
    //得到真实验证码
    String code = captchaUtil.getCode();
    long endTime = System.currentTimeMillis();
    System.out.println("验证码为:" + code + "\n花费时间为:" + (endTime - startend) + "\n到E盘根目录下看,文件名为11.jpg");
  }

  public BufferedImage getImage() {
    //图片缓冲区
    BufferedImage image = new BufferedImage(width, height, 1);
    //获得笔
    Graphics graphics = image.getGraphics();
    //设置初始画笔为白色
    graphics.setColor(new Color(255, 255, 254));
    //画满整个图,也就是把图片先变为白色
    graphics.fillRect(0, 0, width, height);
    Random rd = new Random();
    //设置字体
    Font font = new Font("宋体", Font.PLAIN, 35 + rd.nextInt(10));
    graphics.setFont(font);
    char[] chars = "qweCRYHrtasdfBxy678934VTGopNUFKuighjklzSXEDLOP12cvbnmQAZWJMI50".toCharArray();
    //画验证码
    for (int i = 0; i < count; i++) {
      String string = "";
      string += chars[rd.nextInt(chars.length)] + "";
      graphics.setColor(new Color(rd.nextInt(254), rd.nextInt(254), rd.nextInt(254)));
      graphics.drawString(string, 55 * i + rd.nextInt(10), 27 + rd.nextInt(15));
      code += string;
    }
    //干扰点
    for (int i = 0; i < 25 * count; i++) {
      graphics.setFont(new Font("宋体", Font.PLAIN, 15));
      String string = ".";
      graphics.setColor(new Color(rd.nextInt(255), rd.nextInt(255), rd.nextInt(255)));
      graphics.drawString(string, rd.nextInt(width), rd.nextInt(height));
    }
    //干扰线
    for (int i = 0; i < count + count / 2; i++) {
      graphics.setFont(new Font("宋体", Font.PLAIN, 10));
      graphics.setColor(new Color(rd.nextInt(255), rd.nextInt(255), rd.nextInt(255)));
      graphics.drawLine(rd.nextInt(width), rd.nextInt(height), rd.nextInt(width), rd.nextInt(height));
    }
    //归还笔
    graphics.dispose();
    //写到流里面需要用到ImageIo
    //这里做的测试,在本地测试下是否画的是那回事
          /*try {
              ImageIO.write(image,"jpg",new FileOutputStream("E:/11.jpg"));
          } catch (IOException e) {
              e.printStackTrace();
          }*/
    this.bufferedImage = image;
    return image;
  }
  
  public static String getBase64(BufferedImage image) {
    String base64 = null;
    try {
      //输出流
      ByteArrayOutputStream stream = new ByteArrayOutputStream();
      ImageIO.write(image, "png", stream);
      base64 = Base64.encode(stream.toByteArray());
      log.info("生成的图片验证码base64:{}", base64);
    } catch (IOException e) {
      log.error("生成生成的图片验证码base64失败:{}", e.getMessage());
      e.printStackTrace();
    }
    return base64;

  }
}

4、前端发送 axios 请求 来获取 验证码

// 获取验证码

getCode() {
  // 请求后台验证码
  throw axios.get("/captcha/getCaptcha",).then(res => {
    if (res.data.code === 0) {
    	// 给 图片的 src 赋值
      this.codeImg = res.data.data.img;
		//  给 UUID 赋值
      this.imgUUID = res.data.data.imgUUID;
  
    //   this.code = res.data.data.code;
      console.log(this.code)
    } else {
      this.$message.error(res.data.msg)
    }
  }).catch(error => {
    alert("errorAjax")
  })
},

5、验证码的显示

<img :src="'data:image/gif;base64,'+ codeImg" 
alt="验证码获取失败!" title="看不清?换一张!" class="codeImg"
 width="80%" @click="getCode()">

6、后端的处理

  @ApiOperation(value = "获取验证码")
  @GetMapping("/getCaptcha")
  @ResponseBody
  public Result getCaptcha() {
    //画图工具类
    CaptchaUtil imageCode = new CaptchaUtil();
    // 获取验证码对应的 base64  编码
    String base64 = CaptchaUtil.getBase64(imageCode.getImage());
    // 获取对应的 验证码 code
    String code = imageCode.getCode();
    // 生成 UUID
    String imgUUID = UUIDUtil.get32UUID();
    // 封装 获取的 验证码相关的数据 到 验证码对象中,并响应
    ImgResult imgResult = new ImgResult();
    imgResult.setImgUUID(imgUUID);
    imgResult.setImg(base64);
    imgResult.setCode(code);
    // 将验证码的信息保存到 redis中,并设置 有效时间2分钟!
    redisUtil.hset("captchaCache:", imgUUID, code, 120);
    // 将封装好的验证码对象响应给前端
    return Result.success(imgResult);
  }

UUID工具类如下:

package com.sany.crane.oa.common.util;

import java.util.UUID;

public class UUIDUtil {
  /**
    * 获得4个长度的十六进制的UUID
    *
    * @return UUID
    */
   public static String get4UUID() {
    UUID id = UUID.randomUUID();
    String[] idd = id.toString().split("-");
    return idd[1];
   }

   /**
    * 获得8个长度的十六进制的UUID
    *
    * @return UUID
    */
   public static String get8UUID() {
    UUID id = UUID.randomUUID();
    String[] idd = id.toString().split("-");
    return idd[0];
   }

   /**
    * 获得12个长度的十六进制的UUID
    *
    * @return UUID
    */
   public static String get12UUID() {
    UUID id = UUID.randomUUID();
    String[] idd = id.toString().split("-");
    return idd[0] + idd[1];
   }

   /**
    * 获得16个长度的十六进制的UUID
    *
    * @return UUID
    */
   public static String get16UUID() {

    UUID id = UUID.randomUUID();
    String[] idd = id.toString().split("-");
    return idd[0] + idd[1] + idd[2];
   }

   /**
    * 获得20个长度的十六进制的UUID
    *
    * @return UUID
    */
   public static String get20UUID() {

    UUID id = UUID.randomUUID();
    String[] idd = id.toString().split("-");
    return idd[0] + idd[1] + idd[2] + idd[3];
   }

   /**
    * 获得24个长度的十六进制的UUID
    *
    * @return UUID
    */
   public static String get24UUID() {
    UUID id = UUID.randomUUID();
    String[] idd = id.toString().split("-");
    return idd[0] + idd[1] + idd[4];
   }

   /**
    * 获得32个长度的十六进制的UUID
    *
    * @return UUID
    */
   public static String get32UUID() {
    UUID id = UUID.randomUUID();
    String[] idd = id.toString().split("-");
    return idd[0] + idd[1] + idd[2] + idd[3] + idd[4];
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值