Java實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼的示例代碼
最近滑動(dòng)驗(yàn)證碼在很多網(wǎng)站逐步流行起來(lái),一方面對(duì)用戶體驗(yàn)來(lái)說(shuō),比較新穎,操作簡(jiǎn)單,另一方面相對(duì)圖形驗(yàn)證碼來(lái)說(shuō),安全性并沒(méi)有很大的降低。當(dāng)然到目前為止,沒(méi)有絕對(duì)的安全驗(yàn)證,只是不斷增加攻擊者的繞過(guò)成本。
接下來(lái)分析下滑動(dòng)驗(yàn)證碼的核心流程:
后端隨機(jī)生成摳圖和帶有摳圖陰影的背景圖片,后臺(tái)保存隨機(jī)摳圖位置坐標(biāo)
前端實(shí)現(xiàn)滑動(dòng)交互,將摳圖拼在摳圖陰影之上,獲取到用戶滑動(dòng)距離值,比如以下示例

前端將用戶滑動(dòng)距離值傳入后端,后端校驗(yàn)誤差是否在容許范圍內(nèi)。
這里單純校驗(yàn)用戶滑動(dòng)距離是最基本的校驗(yàn),出于更高的安全考慮,可能還會(huì)考慮用戶滑動(dòng)的整個(gè)軌跡,用戶在當(dāng)前頁(yè)面的訪問(wèn)行為等。這些可以很復(fù)雜,甚至借助到用戶行為數(shù)據(jù)分析模型,最終的目標(biāo)都是增加非法的模擬和繞過(guò)的難度。這些有機(jī)會(huì)可以再歸納總結(jié)常用到的方法,本文重點(diǎn)集中在如何基于Java來(lái)一步步實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼的生成。
可以看到,滑動(dòng)圖形驗(yàn)證碼,重要有兩個(gè)圖片組成,摳塊和帶有摳塊陰影的原圖,這里面有兩個(gè)重要特性保證被暴力破解的難度:摳塊的形狀隨機(jī)和摳塊所在原圖的位置隨機(jī)。這樣就可以在有限的圖集中制造出隨機(jī)的、無(wú)規(guī)律可尋的摳圖和原圖的配對(duì)。
用代碼如何從一張大圖中摳出一個(gè)有特定隨機(jī)形狀的小圖呢?
第一步,先確定一個(gè)摳出圖的輪廓,方便后續(xù)真正開(kāi)始執(zhí)行圖片處理操作
圖片是有像素組成,每個(gè)像素點(diǎn)對(duì)應(yīng)一種顏色,顏色可以用RGB形式表示,外加一個(gè)透明度,把一張圖理解成一個(gè)平面圖形,左上角為原點(diǎn),向右x軸,向下y軸,一個(gè)坐標(biāo)值對(duì)應(yīng)該位置像素點(diǎn)的顏色,這樣就可以把一張圖轉(zhuǎn)換成一個(gè)二維數(shù)組?;谶@個(gè)考慮,輪廓也用二維數(shù)組來(lái)表示,輪廓內(nèi)元素值為1,輪廓外元素值對(duì)應(yīng)0。
這時(shí)候就要想這個(gè)輪廓形狀怎么生成了。有坐標(biāo)系、有矩形、有圓形,沒(méi)錯(cuò),用到數(shù)學(xué)的圖形函數(shù)。典型用到一個(gè)圓的函數(shù)方程和矩形的邊線的函數(shù),類似:
(x-a)²+(y-b)²=r²中,有三個(gè)參數(shù)a、b、r,即圓心坐標(biāo)為(a,b),半徑r。這些將摳圖放在上文描述的坐標(biāo)系上很容易就圖算出來(lái)具體的值。
示例代碼如下:
private int[][] getBlockData() {
int[][] data = new int[targetLength][targetWidth];
double x2 = targetLength-circleR-2;
//隨機(jī)生成圓的位置
double h1 = circleR + Math.random() * (targetWidth-3*circleR-r1);
double po = circleR*circleR;
double xbegin = targetLength-circleR-r1;
double ybegin = targetWidth-circleR-r1;
for (int i = 0; i < targetLength; i++) {
for (int j = 0; j < targetWidth; j++) {
//右邊○
double d3 = Math.pow(i - x2,2) + Math.pow(j - h1,2);
if (d1 <= po
|| (j >= ybegin && d2 >= po)
|| (i >= xbegin && d3 >= po)
) {
data[i][j] = 0;
} else {
data[i][j] = 1;
}
}
}
return data;
}
第二步,有這個(gè)輪廓后就可以依據(jù)這個(gè)二維數(shù)組的值來(lái)判定摳圖并在原圖上摳圖位置處加陰影。
操作如下:
private void cutByTemplate(BufferedImage oriImage,BufferedImage targetImage, int[][] templateImage, int x,
int y){
for (int i = 0; i < targetLength; i++) {
for (int j = 0; j < targetWidth; j++) {
int rgb = templateImage[i][j];
// 原圖中對(duì)應(yīng)位置變色處理
int rgb_ori = oriImage.getRGB(x + i, y + j);
if (rgb == 1) {
//摳圖上復(fù)制對(duì)應(yīng)顏色值
targetImage.setRGB(i, y + j, rgb_ori);
int r = (0xff & rgb_ori);
int g = (0xff & (rgb_ori >> 8));
int b = (0xff & (rgb_ori >> 16)));
rgb_ori = r + (g << 8) + (b << 16) + (200 << 24);
//原圖對(duì)應(yīng)位置顏色變化
oriImage.setRGB(x + i, y + j, rgb_ori);
}
}
}
}
經(jīng)過(guò)前面兩步后,就得到了摳圖和帶摳圖陰影的原圖。為增加混淆和提高網(wǎng)絡(luò)加載效果,還需要對(duì)圖片做進(jìn)一步處理。一般有兩件事需要做,一對(duì)圖片做模糊處理增加機(jī)器識(shí)別難度,二做適當(dāng)同質(zhì)量壓縮。模糊處理很容易想到高斯模糊,原理很好理解,大家可以去google了解下。具體到Java里面的實(shí)現(xiàn),有很多版本,現(xiàn)在不借助任何第三方j(luò)ar,提供一個(gè)示例:
public static ConvolveOp getGaussianBlurFilter(int radius,
boolean horizontal) {
if (radius < 1) {
throw new IllegalArgumentException("Radius must be >= 1");
}
int size = radius * 2 + 1;
float[] data = new float[size];
float sigma = radius / 3.0f;
float twoSigmaSquare = 2.0f * sigma * sigma;
float sigmaRoot = (float) Math.sqrt(twoSigmaSquare * Math.PI);
float total = 0.0f;
for (int i = -radius; i <= radius; i++) {
float distance = i * i;
int index = i + radius;
data[index] = (float) Math.exp(-distance / twoSigmaSquare) / sigmaRoot;
total += data[index];
}
for (int i = 0; i < data.length; i++) {
data[i] /= total;
}
Kernel kernel = null;
if (horizontal) {
kernel = new Kernel(size, 1, data);
} else {
kernel = new Kernel(1, size, data);
}
return new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
}
public static void simpleBlur(BufferedImage src,BufferedImage dest) {
BufferedImageOp op = getGaussianBlurFilter(2,false);
op.filter(src, dest);
}
經(jīng)測(cè)試模糊效果很不錯(cuò)。另外是圖片壓縮,也不借助任何第三方工具,做同質(zhì)壓縮。
public static byte[] fromBufferedImage2(BufferedImage img,String imagType) throws IOException {
bos.reset();
// 得到指定Format圖片的writer
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(imagType);
ImageWriter writer = (ImageWriter) iter.next();
// 得到指定writer的輸出參數(shù)設(shè)置(ImageWriteParam )
ImageWriteParam iwp = writer.getDefaultWriteParam();
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); // 設(shè)置可否壓縮
iwp.setCompressionQuality(1f); // 設(shè)置壓縮質(zhì)量參數(shù)
iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED);
ColorModel colorModel = ColorModel.getRGBdefault();
// 指定壓縮時(shí)使用的色彩模式
iwp.setDestinationType(new javax.imageio.ImageTypeSpecifier(colorModel,
colorModel.createCompatibleSampleModel(16, 16)));
writer.setOutput(ImageIO
.createImageOutputStream(bos));
IIOImage iIamge = new IIOImage(img, null, null);
writer.write(null, iIamge, iwp);
byte[] d = bos.toByteArray();
return d;
}
至此,滑動(dòng)驗(yàn)證碼核心的代碼處理流程已全部結(jié)束,這里面有很多細(xì)節(jié)可以不斷打磨優(yōu)化,讓滑動(dòng)體驗(yàn)可以變得更好。希望可以幫助到某些準(zhǔn)備自己構(gòu)建滑動(dòng)驗(yàn)證碼的同學(xué)。
以上代碼實(shí)現(xiàn)都非常的精煉,一方面為了保證性能,另一方面好理解。另外由于各方面原因也不便引入過(guò)多細(xì)節(jié),如果疑問(wèn),可留言交流。經(jīng)測(cè)試,該生成滑動(dòng)圖形的流程響應(yīng)時(shí)間可以控制在20ms左右,如果原圖分辨率在300px*150px以下,可以到10ms左右,在可接受范圍內(nèi)。如果有更高效的方式,希望多多指教。也希望大家多多支持腳本之家。
- java登錄驗(yàn)證碼實(shí)現(xiàn)代碼
- java 圖片驗(yàn)證碼的實(shí)現(xiàn)代碼
- Java實(shí)現(xiàn)驗(yàn)證碼具體代碼
- Java 隨機(jī)生成驗(yàn)證碼(支持大小寫字母、數(shù)字、隨機(jī)字體)的實(shí)例
- JAVA實(shí)現(xiàn)利用第三方平臺(tái)發(fā)送短信驗(yàn)證碼
- Java隨機(jī)生成手機(jī)短信驗(yàn)證碼的方法
- Java實(shí)現(xiàn)仿淘寶滑動(dòng)驗(yàn)證碼研究代碼詳解
- java實(shí)現(xiàn)短信驗(yàn)證碼5分鐘有效時(shí)間
- JavaWeb簡(jiǎn)單用戶登錄注冊(cè)實(shí)例代碼(有驗(yàn)證碼)
- java實(shí)現(xiàn)隨機(jī)驗(yàn)證碼圖片生成
相關(guān)文章
JavaWeb購(gòu)物車項(xiàng)目開(kāi)發(fā)實(shí)戰(zhàn)指南
之前沒(méi)有接觸過(guò)購(gòu)物車的東東,也不知道購(gòu)物車應(yīng)該怎么做,所以在查詢了很多資料,總結(jié)一下購(gòu)物車的功能實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于JavaWeb購(gòu)物車項(xiàng)目開(kāi)發(fā)的相關(guān)資料,需要的朋友可以參考下2022-06-06
Java之CMS和G1垃圾回收過(guò)程的異同說(shuō)明
CMS垃圾回收器主要基于并發(fā)-清理算法,目的是減少停頓時(shí)間,通過(guò)四個(gè)主要階段進(jìn)行垃圾回收:初始標(biāo)記、并發(fā)標(biāo)記、重新標(biāo)記和并發(fā)清理,G1垃圾回收器采用標(biāo)記-整理算法,是JDK9后的默認(rèn)垃圾收集器,設(shè)計(jì)為全功能全代收集器2024-09-09
詳解Java使用雙異步后如何保證數(shù)據(jù)一致性
這篇文章主要為大家詳細(xì)介紹了Java使用雙異步后如何保證數(shù)據(jù)一致性,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以了解下2024-01-01
Java 通過(guò)AQS實(shí)現(xiàn)數(shù)據(jù)組織
這篇文章主要介紹了通過(guò)AQS實(shí)現(xiàn)數(shù)據(jù)組織,想了解AQS的同學(xué)可以參考下2021-04-04
關(guān)于SpringCloud?Ribbon替換輪詢算法問(wèn)題
Spring?Cloud?Ribbon是基于Netlix?Ribbon實(shí)現(xiàn)的一套客戶端負(fù)載均衡的工具。接下來(lái)通過(guò)本文給大家介紹SpringCloud?Ribbon替換輪詢算法問(wèn)題,需要的朋友可以參考下2022-01-01
SpringBoot項(xiàng)目中的視圖解析器問(wèn)題(兩種)
SpringBoot官網(wǎng)推薦使用HTML視圖解析器,但是根據(jù)個(gè)人的具體業(yè)務(wù)也有可能使用到JSP視圖解析器,所以本文介紹了兩種視圖解析器,感興趣的可以了解下2020-06-06
java實(shí)現(xiàn)單機(jī)版五子棋小游戲
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)單機(jī)版五子棋小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12
Java AQS中ReentrantReadWriteLock讀寫鎖的使用
ReentrantReadWriteLock稱為讀寫鎖,它提供一個(gè)讀鎖,支持多個(gè)線程共享同一把鎖。這篇文章主要講解一下ReentrantReadWriteLock的使用和應(yīng)用場(chǎng)景,感興趣的可以了解一下2023-02-02

