一、什么是圖片驗證碼?
可以參考下面這張圖:

我們在一些網站注冊的時候,經常需要填寫以上圖片的信息。
這種圖片驗證方式是我們最常見的形式,它可以有效的防范惡意攻擊者采用惡意工具,調用“動態驗證碼短信獲取”接口進行動態短信發送, 導致接入用戶短信被刷,造成賬號余額損失。同時這種動態發送方式會朝許多無關的手機用戶,發送很多驗證碼短信,導致手機用戶被騷擾,甚至引起用戶投訴。這種惡意攻擊究其原因是攻擊者可以自動對接口進行大量調用。
如果網站在用戶進行“動態驗證碼短信發送” 操作前,要求用戶輸入圖片驗證碼,確認用戶是真實有效后,服務器端再發送動態短信到用戶手機上。這一種流程就可以有效的解決惡意攻擊問題。
正確的加入圖片驗證碼的方式是在短信驗證碼發送前,先讓用戶填寫圖片驗證碼,再發送短信驗證碼。
舉一個正確的例子(下圖)

說了這么多,具體是怎么實現的呢?
1、圖片生成實體類:
package com.hexianwei.graphic;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
public class ImageVerificationCode {
private int weight = 100; //驗證碼圖片的長和寬
private int height = 40;
private String text; //用來保存驗證碼的文本內容
private Random r = new Random(); //獲取隨機數對象
//private String[] fontNames = {"宋體", "華文楷體", "黑體", "微軟雅黑", "楷體_GB2312"}; //字體數組
//字體數組
private String[] fontNames = {"Georgia"};
//驗證碼數組
private String codes = "23456789abcdefghjkmnopqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ";
/**
* 獲取隨機的顏色
*
* @return
*/
private Color randomColor() {
int r = this.r.nextInt(225); //這里為什么是225,因為當r,g,b都為255時,即為白色,為了好辨認,需要顏色深一點。
int g = this.r.nextInt(225);
int b = this.r.nextInt(225);
return new Color(r, g, b); //返回一個隨機顏色
}
/**
* 獲取隨機字體
*
* @return
*/
private Font randomFont() {
int index = r.nextInt(fontNames.length); //獲取隨機的字體
String fontName = fontNames[index];
int style = r.nextInt(4); //隨機獲取字體的樣式,0是無樣式,1是加粗,2是斜體,3是加粗加斜體
int size = r.nextInt(10) + 24; //隨機獲取字體的大小
return new Font(fontName, style, size); //返回一個隨機的字體
}
/**
* 獲取隨機字符
*
* @return
*/
private char randomChar() {
int index = r.nextInt(codes.length());
return codes.charAt(index);
}
/**
* 畫干擾線,驗證碼干擾線用來防止計算機解析圖片
*
* @param image
*/
private void drawLine(BufferedImage image) {
int num = r.nextInt(10); //定義干擾線的數量
Graphics2D g = (Graphics2D) image.getGraphics();
for (int i = 0; i < num; i++) {
int x1 = r.nextInt(weight);
int y1 = r.nextInt(height);
int x2 = r.nextInt(weight);
int y2 = r.nextInt(height);
g.setColor(randomColor());
g.drawLine(x1, y1, x2, y2);
}
}
/**
* 創建圖片的方法
*
* @return
*/
private BufferedImage createImage() {
//創建圖片緩沖區
BufferedImage image = new BufferedImage(weight, height, BufferedImage.TYPE_INT_RGB);
//獲取畫筆
Graphics2D g = (Graphics2D) image.getGraphics();
//設置背景色隨機
g.setColor(new Color(255, 255, r.nextInt(245) + 10));
g.fillRect(0, 0, weight, height);
//返回一個圖片
return image;
}
/**
* 獲取驗證碼圖片的方法
*
* @return
*/
public BufferedImage getImage() {
BufferedImage image = createImage();
Graphics2D g = (Graphics2D) image.getGraphics(); //獲取畫筆
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 4; i++) //畫四個字符即可
{
String s = randomChar() + ""; //隨機生成字符,因為只有畫字符串的方法,沒有畫字符的方法,所以需要將字符變成字符串再畫
sb.append(s); //添加到StringBuilder里面
float x = i * 1.0F * weight / 4; //定義字符的x坐標
g.setFont(randomFont()); //設置字體,隨機
g.setColor(randomColor()); //設置顏色,隨機
g.drawString(s, x, height - 5);
}
this.text = sb.toString();
drawLine(image);
return image;
}
/**
* 獲取驗證碼文本的方法
*
* @return
*/
public String getText() {
return text;
}
public static void output(BufferedImage image, OutputStream out) throws IOException //將驗證碼圖片寫出的方法
{
ImageIO.write(image, "JPEG", out);
}
}
2、在控制器中把圖片響應給前端頁面(ssm框架)
@RequestMapping("getVerifiCode")
@ResponseBody
public void getVerifiCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
/*
1.生成驗證碼
2.把驗證碼上的文本存在session中
3.把驗證碼圖片發送給客戶端
*/
ImageVerificationCode ivc = new ImageVerificationCode(); //用我們的驗證碼類,生成驗證碼類對象
BufferedImage image = ivc.getImage(); //獲取驗證碼
request.getSession().setAttribute("text", ivc.getText()); //將驗證碼的文本存在session中
ivc.output(image, response.getOutputStream());//將驗證碼圖片響應給客戶端
}
3、從session獲得驗證碼字符(ssm框架)
@RequestMapping("Login_authentication")
@ResponseBody
public String Login_authentication(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
String session_vcode=(String) request.getSession().getAttribute("text"); //從session中獲取真正的驗證碼
return session_vcode;
}
4、前端請求圖片
<a href="javascript:getVerifiCode()">
<img id="yzm_img" style="cursor:pointer;width: 100px;height: 36px;margin: 5px 0 0 5px;border-radius: 3px;" title="點擊刷新驗證碼" src="Mcake/getVerifiCode"/>
</a>
function getVerifiCode() {
$("#yzm_img").prop('src','Mcake/getVerifiCode?a='+new Date().getTime());
}
5、效果:


