基本原理
现在无论是app还是web登录时一般都需要一个验证码,用来防止暴力破解,基本原理是,后端生产一个随机字符串,将字符串变成一个图片,将图片返回给前端显示,在验证时,前端在给后端传账号,密码的同时传这个验证码,为了能正确校验这个字符串,前端在获取这个验证码时需要生成一个uuid,后端依据uuid查找验证码进行校验。
前端工作
构造一个现实图片的控件,同时这个控件在点击时获取新的验证码,并刷新图片。
代码
import { makeStyles } from “@mui/styles”;
import { useState } from “react”;
import uuid from “react-uuid”;
const useStyles=makeStyles({
root:{
padding:‘16.5px 14px’,
margin:‘16px’
}
})
export default function ImageButton(props){
const [code,setCode]=useState(“”)
const classes=useStyles()
return <img src={props.src+“&”+code} onClick={()=>setCode(uuid())} className={classes.root} alt=“验证码”>
}
代码说明
最简单的函数控件
使用useStyle调整下位置。
控件只有一个img,src的属性就是后端返回的图片url。img增加一个点击事件,通过hook绑定一个随机数(code),点击时生成新的随机数,img的src属性就会变化,控件获取到新的图片,并且刷新控件。
后端工作
生成验证码图片。
//controller代码
@GetMapping(“code”)
public void getVerifyCode(@RequestParam(name = “uuid”,required = false)String uuid,
HttpServletResponse response){
try {
BufferedImage image = verifyCodeService.getCode(uuid).getData();
response.setContentType(“image/png”);
OutputStream os = response.getOutputStream();
ImageIO.write(image, “png”, os);
}catch (Exception e){
log.error(“”,e);
}
}
//service代码
public ResponseVO getCode(String uuid) {
if(StringUtils.isBlank(uuid)){
return ResponseVOWrapper.buildFail(UserEnum.VERIFYCODEERROR);
}
Object[] objects = VerifyUtil.createImage();
String code=(String) objects[0];
BufferedImage image = (BufferedImage) objects[1];
log.debug("uuid={},code={}",uuid,code);
VerifyCodeDO verifyCodeDO=verifyCodeRepository.getByUUID(uuid);
log.debug("{}",verifyCodeDO);
if(verifyCodeDO==null){
verifyCodeDO=new VerifyCodeDO();
verifyCodeDO.setUuid(uuid);
verifyCodeDO.setCode(code);
verifyCodeRepository.addVerifyCode(verifyCodeDO);
}else {
verifyCodeDO.setSms("");
verifyCodeDO.setLastTime(null);
verifyCodeDO.setCode(code);
verifyCodeRepository.updateVerifyCode(verifyCodeDO);
}
return ResponseVOWrapper.buildSuccess(image);
}
校验验证码
public Boolean checkCode(String uuid, String code) {
VerifyCodeDO verifyCodeDO= verifyCodeRepository.getByUUID(uuid);
if(verifyCodeDO==null||StringUtils.isBlank(verifyCodeDO.getCode())){
return false;
}
if(!verifyCodeDO.getCode().toLowerCase().equals(code.toLowerCase())){
verifyCodeDO.setCode("");
verifyCodeRepository.updateVerifyCode(verifyCodeDO);
return false;
}
verifyCodeDO.setCode("");
verifyCodeRepository.updateVerifyCode(verifyCodeDO);
return true;
}
代码说明
生成随机字符串,根据字符串生成BufferImage,返回给前端。
生成的随机字符串,存入数据库,主键为前端给的uuid。
验证,使用uuid从数据库查询记录,并比对。正确的返回true,不正确的返回false,并且删除已有的字符串,并重新生成。