家好!我是黑客之家小編,黑客之家頭條號(hào)
分享黑客技術(shù),GO、Python、Kotlin、Android、Java編程知識(shí),科技資訊等
喜歡的朋友可以關(guān)注我的頭條號(hào)!
圖形驗(yàn)證碼是我們經(jīng)常會(huì)用到的,例如在app或者網(wǎng)站注冊(cè)的時(shí)候,登錄的時(shí)候等等。圖形驗(yàn)證碼屬于驗(yàn)證碼的一種。
圖形驗(yàn)證碼
驗(yàn)證碼(CAPTCHA)是 “Completely Automated Public Turing test to tell Computers and Humans Apart”(全自動(dòng)區(qū)分計(jì)算機(jī)和人類的圖靈測(cè)試)的縮寫,是一種區(qū)分用戶是計(jì)算機(jī)還是人的公共全自動(dòng)程序。
采用圖形驗(yàn)證碼是為了數(shù)據(jù)的安全,防止某些破解軟件,進(jìn)行無限嘗試破解,圖形的話,軟件無法識(shí)別,或識(shí)別的慢,這樣更加安全。
理論上圖形驗(yàn)證碼是比較安全的,但是隨著技術(shù)的發(fā)展,特別是機(jī)器學(xué)習(xí)和人工智能技術(shù)的發(fā)展,圖形驗(yàn)證碼也變得不安全了,今天我們將要生成的數(shù)字字母組合的驗(yàn)證碼,其實(shí)已經(jīng)不夠安全了,生成效果如下:
這種驗(yàn)證碼還是容易被機(jī)器識(shí)別的,后續(xù)的文章中會(huì)介紹如何采用程序識(shí)別這類圖形驗(yàn)證碼。
接著說圖形驗(yàn)證碼的生成,今天我們采用的是kaptcha。kaptcha是一個(gè)可配置驗(yàn)證碼生成工具包,我們按照kaptcha的配置表配置就可以了。
在使用kaptcha之前,要導(dǎo)入kaptcha的包,依賴如下:
<dependency> <groupId>com.github.penggle</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency>
在Spring Boot項(xiàng)目中新建一個(gè)KaptchaConfig.java文件,具體代碼如下:
package com.example.demo.config; /** * Created by hacker on 2019-07-16. */ import com.google.code.kaptcha.impl.DefaultKaptcha; import com.google.code.kaptcha.util.Config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Properties; /** * @author hacker */ @Configuration public class KaptchaConfig { @Bean public DefaultKaptcha getDefaultKaptcha() { DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); Properties properties = new Properties(); properties.setProperty("kaptcha.border", "yes"); properties.setProperty("kaptcha.border.color", "105,179,90"); properties.setProperty("kaptcha.textproducer.font.color", "blue"); properties.setProperty("kaptcha.image.width", "110"); properties.setProperty("kaptcha.image.height", "40"); properties.setProperty("kaptcha.textproducer.font.size", "30"); properties.setProperty("kaptcha.session.key", "code"); properties.setProperty("kaptcha.textproducer.char.length", "4"); properties.setProperty("kaptcha.textproducer.font.names", "宋體,楷體,微軟雅黑"); Config config = new Config(properties); defaultKaptcha.setConfig(config); return defaultKaptcha; } }
這樣kaptcha的樣式和顏色字體等就設(shè)置好了,接著就是生成圖形上的字符,同時(shí)通過二進(jìn)制流的形式把生成的圖片返回給前端。
代碼如下:
package com.example.demo.controller; import com.google.code.kaptcha.impl.DefaultKaptcha; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.imageio.ImageIO; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; /** * <p> * 用戶信息表 前端控制器 * </p> * * @author hacker */ @RestController @RequestMapping("/api/") public class UserInfoController { @Autowired private DefaultKaptcha captchaProducer; @GetMapping("/getVerifyCode") public void getVerifyCode(HttpServletRequest request, HttpServletResponse response) throws Exception { String createText = captchaProducer.createText(); request.getSession().setAttribute("verifyCode", createText); response.setHeader("Cache-Control", "no-store"); response.setHeader("Pragma", "no-cache"); response.setDateHeader("Expires", 0); response.setContentType("image/jpeg"); BufferedImage challenge = captchaProducer.createImage(createText); ServletOutputStream outputStream = response.getOutputStream(); ImageIO.write(challenge, "jpg", outputStream); try { outputStream.flush(); } finally { outputStream.close(); } } }
這樣我們就可以用GET方式獲取到生成的圖形驗(yàn)證碼了。
為了能在瀏覽器里顯示我們這里采用thymeleaf模板。
在pom.xml文件中引入thymeleaf依賴如下:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
之后在templates文件夾下新建一個(gè)index.html文件,代碼如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>CAPTCHA</title> <script type="text/javascript"> function refresh() { document.getElementById('captcha_img').src = "/api/getVerifyCode?" + Math.random(); } </script> </head> <body> <div> <img id="captcha_img" alt="點(diǎn)擊更換" title="點(diǎn)擊更換" onclick="refresh()" src="/api/getVerifyCode"/> </div> </body> </html>
這樣一個(gè)簡(jiǎn)單前端顯示圖形驗(yàn)證碼就做好了,之后我們輸入http://localhost:8090/,就可以訪問了,8090換成自己對(duì)應(yīng)的端口。
圖形驗(yàn)證碼
點(diǎn)擊圖片可以切換圖形驗(yàn)證碼。至此,圖形驗(yàn)證碼功能結(jié)束!
如果覺得文章對(duì)你有幫助,歡迎關(guān)注,點(diǎn)贊,轉(zhuǎn)發(fā),評(píng)論!后續(xù)文章會(huì)介紹如何通過程序識(shí)別今天生成的圖形驗(yàn)證碼,感興趣的同學(xué),可以持續(xù)關(guān)注!
相關(guān)閱讀:
基于spring boot快速搭建Java服務(wù)器
Spring Boot項(xiàng)目部署簡(jiǎn)單方便的Shell腳本
推薦一款Spring Boot中非常好用的插件
網(wǎng)頁設(shè)計(jì)中,尤其表單填寫提交過程中,為防止機(jī)器自動(dòng)登錄,很多網(wǎng)頁都采用驗(yàn)證碼技術(shù),允許用戶輸入而盡量避免自動(dòng)登錄。驗(yàn)證碼實(shí)現(xiàn)的方法有很多,PHP繪圖技術(shù)可以在服務(wù)端生成驗(yàn)證碼并發(fā)送客戶端,HTML5技術(shù)下可以使用canvas與JS腳本實(shí)現(xiàn)在客戶端瀏覽器自動(dòng)生成驗(yàn)證碼。本文給出JS+Canvas驗(yàn)證碼的解決措施,所制作驗(yàn)證碼實(shí)現(xiàn)效果如下圖所示:
驗(yàn)證碼實(shí)現(xiàn)效果動(dòng)態(tài)圖
本例驗(yàn)證碼的實(shí)現(xiàn)主要包括驗(yàn)證碼字符串的生成、背景干擾點(diǎn)實(shí)現(xiàn)及干擾直線的生成三部分。最終通過canvas繪圖技術(shù)將生成的驗(yàn)證碼字符串、背景及干擾直線顯示到畫布上。主要涉及技術(shù)或知識(shí)點(diǎn)包括canvas繪圖技術(shù)、數(shù)組、鼠標(biāo)點(diǎn)擊事件、隨機(jī)函數(shù)等。以下從驗(yàn)證字符串、背景干擾點(diǎn)及干擾直線三方面對(duì)實(shí)現(xiàn)過程進(jìn)行說明。
驗(yàn)證字符串部分主要借助數(shù)組存儲(chǔ)驗(yàn)證碼所有字符,通過調(diào)用Math對(duì)象的隨機(jī)函數(shù)獲取數(shù)組下標(biāo),并通過數(shù)組下表讀取數(shù)組元素,將讀取的數(shù)組元素組裝成完整字符串。其實(shí)現(xiàn)核心代碼如下:
驗(yàn)證字符串獲取核心代碼
如上圖所示,本例驗(yàn)證碼字符包括數(shù)字與大寫字母,getCode函數(shù)返回值即為4位驗(yàn)證碼字符串。
背景干擾點(diǎn)可以直接使用canvas對(duì)應(yīng)的繪圖方法進(jìn)行繪制,本例為簡(jiǎn)化開發(fā)過程,降低難度直接使用drawImage繪圖方式加載背景圖片,實(shí)現(xiàn)干擾點(diǎn)效果。背景圖片如下:
背景干擾點(diǎn)圖片
通過調(diào)用drawImage方法,指定截取的坐標(biāo)位置參數(shù),可實(shí)現(xiàn)背景干擾點(diǎn)的動(dòng)態(tài)變化效果,背景干擾點(diǎn)實(shí)現(xiàn)核心代碼如下:
背景干擾點(diǎn)實(shí)現(xiàn)代碼
其中g(shù)etXsize與getYsize為獲取繪圖截取背景圖片的坐標(biāo)位置,通過使用隨機(jī)函數(shù)實(shí)現(xiàn)從背景圖片不同位置截取進(jìn)行繪圖輸出。
干擾直線實(shí)現(xiàn)較為簡(jiǎn)單,直接通過JS提供的moveTo與lineTo方法完成直線的繪制,本例繪制了兩條直線,一條為黑色干擾線,一條為白色干擾線。在繪制過程兩端點(diǎn)需要使用Math隨機(jī)函數(shù)生成符合條件隨機(jī)坐標(biāo)。干擾直線相關(guān)實(shí)現(xiàn)代碼如下:
干擾直線實(shí)現(xiàn)核心代碼
干擾直線實(shí)現(xiàn)核心代碼如上圖,其中g(shù)etLsize方法主要用于獲取隨機(jī)端點(diǎn)Y軸坐標(biāo)值。strokeStyle主要用于設(shè)置繪圖直線的顏色。
驗(yàn)證碼的顯示輸出主要使用fillText()方法在canvas指定位置進(jìn)行文字輸出,本例使用第三方ttf字體,因此在HTML頁面中對(duì)字體進(jìn)行了加載。驗(yàn)證碼顯示輸出實(shí)現(xiàn)代碼如下:
驗(yàn)證碼繪制
驗(yàn)證碼顯示輸出核心代碼如上圖所示,其中myfont為加載的第三方字體。
繪圖基礎(chǔ)部分主要包括前端canvas元素的布局等。包括屬性的設(shè)置,js部分元素的獲取及屬性設(shè)置等。
我們一般接觸的驗(yàn)證碼,都可以點(diǎn)擊圖片實(shí)現(xiàn)驗(yàn)證碼的刷新,因此本例為canvas標(biāo)記添加了onclick事件,將所有驗(yàn)證碼生成的代碼封裝到showCode()函數(shù)中,通過調(diào)用showCode函數(shù)實(shí)現(xiàn)驗(yàn)證碼的刷新。本例完整JS腳本部分代碼如下:
JS實(shí)現(xiàn)腳本代碼
本頭條號(hào)長(zhǎng)期關(guān)注編程資訊分享;編程課程、素材、代碼分享及編程培訓(xùn)。如果您對(duì)以上方面有興趣或代碼錯(cuò)誤、建議與意見,可以聯(lián)系作者,共同探討。期待大家關(guān)注!如需案例完整代碼請(qǐng)關(guān)注并私信,往期前端設(shè)計(jì)文章鏈接如下:
近有同事在調(diào)研微信小程序,準(zhǔn)備把我們的 landing page(LP)頁面,遷移到小程序里,提高用戶體驗(yàn),提升轉(zhuǎn)化率。
在LP里,遇到個(gè)很常見的問題,用戶通過手機(jī)號(hào)注冊(cè),發(fā)送短信驗(yàn)證碼需要防刷,目前在 h5 上使用的是 圖形驗(yàn)證碼+極驗(yàn)。一上來,就遇到了圖形驗(yàn)證碼的問題。小程序和 web 開發(fā)不同,不會(huì) 自動(dòng)處理 http 請(qǐng)求的 cookie。
通常在 web 上,我們會(huì)把圖形驗(yàn)證碼存儲(chǔ)到用戶 session 里,然后在發(fā)送短信的接口,判斷用戶提交的圖形驗(yàn)證碼和 session 里的值是否相等,這里依賴瀏覽器自動(dòng)會(huì)處理 cookie 的讀寫來實(shí)現(xiàn)的。但是小程序里,需要開發(fā)者主動(dòng)來管理 cookie 等,并且在圖片請(qǐng)求中,也 不能 主動(dòng)設(shè)置cookie,導(dǎo)致之前 web 上的圖形驗(yàn)證碼完全失效。
在網(wǎng)上發(fā)現(xiàn)提到小程序里的圖形驗(yàn)證碼實(shí)現(xiàn)的文章很少,就有一篇這個(gè) wechat-captcha ,但是作者這是純前端用 canvas 來繪制的圖形驗(yàn)證碼,顯然,圖形驗(yàn)證碼的生成,只能放在 server 端,這種方案,就需要有一種很好的方式,來講server端生成的圖形驗(yàn)證碼的值,傳遞到前端來。沒想到有什么方案,能從server端比較穩(wěn)妥的傳遞圖形驗(yàn)證碼的值到小程序里,只能看看其他大廠是怎么做的了。
server 返回圖片base64編碼
同事發(fā)現(xiàn)餓了么的小程序里,是有圖形驗(yàn)證碼的,那就先來看看餓了么的同學(xué)是怎么實(shí)現(xiàn)的呢。經(jīng)過抓包,很明顯能看到餓了么的圖片驗(yàn)證碼請(qǐng)求,是通過 js 來發(fā)起的,server 端返回的圖形驗(yàn)證碼的 base64 編碼,沒有繼續(xù)看后續(xù)是怎么把 base64 編碼渲染到出來的,但肯定是有辦法將 base64 的圖形驗(yàn)證碼繪制到 canvas 上的。
其實(shí)這里是有個(gè)疑問的,在抓包的時(shí)候,發(fā)現(xiàn)在請(qǐng)求圖形驗(yàn)證碼的時(shí)(POST),并沒有帶上 cookie,也就是說,餓了么并沒有用 cookie-session 來存儲(chǔ)某個(gè)手機(jī)號(hào)對(duì)應(yīng)的圖形驗(yàn)證碼;并且用戶的手機(jī)號(hào),拼在了請(qǐng)求的 url 里,似乎在server端是通過其他方式,來存儲(chǔ)的手機(jī)號(hào)和圖形驗(yàn)證碼的關(guān)聯(lián)。
我不太理解的是,既然用戶手機(jī)號(hào)已經(jīng)放在請(qǐng)求的 path 里了,為什么要使用 POST 來單獨(dú)請(qǐng)求圖驗(yàn)的 base64 編碼,再渲染到 canvas 上,為什么不直接拼一個(gè) GET 的 url,同樣把手機(jī)號(hào)放進(jìn)去,然后接口直接輸出二進(jìn)制的圖片數(shù)據(jù),這樣就可以直接把 url 賦值給小程序的 image 組件了。
餓了么抓包如下(響應(yīng)中的 captcha_image 字段就是 png 圖片的 base64編碼):
使用 WebView
然后又看了下美團(tuán)的小程序,直接沒用圖形驗(yàn)證碼,而是用的類似極驗(yàn)的滑塊。猜想也是使用了 canvas 之類的技術(shù)來實(shí)現(xiàn)的,抓包才發(fā)現(xiàn),原來是用的 web-view組件來引用的 html 頁面。剛重新抓包過程中,雖然后端響應(yīng)接口確實(shí)返回了一個(gè) h5 的滑塊頁面URL,但是沒看到有加載這個(gè)頁面,看來美團(tuán)也 沒有 用 web-view 來加載 h5。
美團(tuán)抓包如下:
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。