数字验证码
数字验证码的生成
生成验证码
@Data
public class ImageCode {
//图形类容
private String code;
//图片
private ByteArrayInputStream image;
//长
private int height=100;
//宽
private int width=400;
public static ImageCode getInstance(){
return new ImageCode();
}
private ImageCode(){
//图形缓冲区,相当于黑板
BufferedImage image=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
//给一支画笔
Graphics graphics = image.getGraphics();
//选择什么颜色的笔
graphics.setColor(new Color(17,147,37));
//拿笔去涂色,画一个矩形
graphics.fillRect(0,0,width,height);
//设置字体
graphics.setFont(new Font("宋体",Font.PLAIN,30));
//图片就中就设置为随机数
Random random =new Random();
this.code="";
for(int i=0;i<6;i++){
//生成随机数
String value = String.valueOf(random.nextInt(10));
//赋值给code
this.code+=value;
//设置画出字的颜色
graphics.setColor(new Color(235,152,37));
//设置画出字在矩形的位置
graphics.drawString(value,(width/6)*i,40);
}
//收笔
graphics.dispose();
ByteArrayInputStream inputStream=null;
try {
ByteOutputStream outputStream =new ByteOutputStream();
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
ImageIO.write(image,"jpeg",imageOutputStream);
inputStream=new ByteArrayInputStream(outputStream.toByteArray());
}catch (Exception e){
System.out.println("数字验证码创建失败");
}
this.image=inputStream;
}
}
在控制层的方法
String attrName="verifyCode";
//控制层调用验证码
@GetMapping("/generator")
public void generatorCode(HttpServletRequest request,HttpServletResponse response){
try {
ImageCode imageCode =ImageCode.getInstance();
//验证码的值
String code = imageCode.getCode();
request.getSession().setAttribute(attrName,code);
//验证码的图片
ByteArrayInputStream image=imageCode.getImage();
response.setContentType("image/jpeg");
byte[] bytes = new byte[1024];
try(ServletOutputStream out =response.getOutputStream()) {
while (image.read(bytes)!=-1){
out.write(bytes);
}
}
}catch (Exception e){
System.out.println("失败输出验证码");
}
}
运行效果
//校验验证码
@GetMapping("/verify")
public String verify(String verifyCode, HttpServletRequest request){
String s = request.getSession().getAttribute(attrName).toString();
System.out.println("校验验证码");
if(verifyCode.equals(s)){
return "验证码校验通过";
}
return "验证码校验失败";
}
校验成功
校验失败
数字验证码的破解
导入依赖
<!--光学识别 OCR-->
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.5.4</version>
</dependency>
可以在github.com/tesseract-o… 下载所需要的语言包
public class TesseractTest {
public static void main(String[] args) throws TesseractException {
//https://github.com/tesseract-ocr/tessdata 语言包
ITesseract iTesseract = new Tesseract();
// 语言包 加进来
iTesseract.setDatapath("语言包的路径");
//中文包
iTesseract.setLanguage("chi_sim");
//英文包
//iTesseract.setLanguage("eng");
File fileDir = new File("d:\data");
for (File file: fileDir.listFiles()){
String s = iTesseract.doOCR(file);
System.out.println(file.getName()+ "识别后数字是:"+s);
}
}
}
需要破解的图片
识别后的结果:
防止办法
可以在验证码上面设置干扰,比如换字体颜色,在验证码上面增加线条,只要是人能识别出来, 机器识别不出来即可
在生成验证码的的代码可以加入划线,来干扰机器的识别率
//划线,可以提高安全
graphics.setColor(new Color(101,2,60));
graphics.drawLine((width/6)*i,40,(width/6)*i+25,40-30);
graphics.drawLine(40,(width/6)*i,40-30,(width/6)*i+25);