JCaptcha 簡介
CAPTCHA 全稱 Completely Automated Public Turing Test to Tell Computers and Humans Apart,最早作為卡內基梅隆大學的一個科研專案,用於生成一個人類容易通過而計算機難以通過的測試,目前廣泛應用於網路應用,用於阻止機器人釋出垃圾資訊。JCaptcha 即為 Java 版本的 CAPTCHA 專案,其是一個開源專案,支援生成圖形和聲音版的驗證碼,在生成聲音版的驗證碼時,需要使用到 FreeTTS。目前,JCaptcha 官方網站顯示有 2.0 版本,但二進位制版只有 1.0 版可供下載,本文亦是基於 1.0 版本展開。
JCaptcha 提供了一定的可擴充套件能力,用於開發人員建立出複雜的圖形驗證碼。下面,首先利用 JCaptcha 提供的 API 來快速開發一個簡單示例。本文的示例為 Web 應用,可以執行在 Tomcat 和 WebSphere 上,除了準備 Web 伺服器外,我們還需要準備好 JCaptcha 執行時所必須的 Jar 包。
JCaptcha 專案在實現中,還引用了 commons-collections 和 commons-logging 兩個開源專案,再加上 JCaptcha 本身的實現,我們共需要三個包,具體資訊如下:
- jcaptcha-1.0-all.jar
- commons-logging-1.1.1.jar
- commons-collections-3.2.jar
在示例 1 中,我們採用 Servlet 生成驗證碼圖片,並將這個圖片寫到 ServletOutputStream 中,同時將 Servlet 的 response 的型別設定為 image/jpeg。在前臺頁面中,我們使用 img 標籤,並將 src 指向這個 Servlet,這樣我們就可以在頁面中顯示這個生成的驗證碼圖片。清單 1 是 Servlet 程式碼片段。
清單 1. 生成圖形驗證碼程式碼片段
// set content type as jpeg httpServletResponse.setHeader("Cache-Control", "no-store"); httpServletResponse.setHeader("Pragma", "no-cache"); httpServletResponse.setDateHeader("Expires", 0); httpServletResponse.setContentType("image/jpeg"); // create the image using session ID logger.fine("tring to get image captcha service"); BufferedImage bufferedImage = service .getImageChallengeForID(httpServletRequest.getSession(true) .getId()); ServletOutputStream servletOutputStream = httpServletResponse .getOutputStream(); // write the image to the servlet output stream logger.fine("tring to output buffered image to servlet output stream"); ImageIO.write(bufferedImage, "jpg", servletOutputStream); try { servletOutputStream.flush(); } finally { servletOutputStream.close(); } |
清單 1 中的 service 物件,我們採用了一個 JCaptcha 的預設實現類 DefaultManageableImageCaptchaService,在程式碼中,我們需要通過獲取 service 物件,根據 Session ID 來生成驗證碼圖片。除了使用該預設實現類外,我們也可以通過實現 ImageCaptchaService 介面來生成更為複雜的驗證碼圖片(參見示例 2)。清單 2 為獲取 service 物件的示例程式碼,JCaptcha 建議使用單例來生成 service 物件。
清單 2. 生成 ImageCaptchaService 物件
public class SampleImageCaptchaService { private static ImageCaptchaService instance; /** * Get default manageable image captcha service * @return ImageCaptchaService */ public static ImageCaptchaService getInstance() { if (instance == null) { instance = new DefaultManageableImageCaptchaService(); } return instance; } } |
示例 1 提供了 2 個簡單的頁面,一個用於顯示圖形驗證碼,另一個則在驗證成功後顯示成功資訊。清單 3 為用於顯示圖形驗證碼的頁面程式碼片段。
清單 3. 顯示圖形驗證碼頁面程式碼片段
<form action="CaptchaValidationServlet" method="post"> <table> <tr> <td colspan="2"><img src="ImageCaptchaServlet" /></td> </tr> <tr> <td> 請輸入您所看到的字元 :</td> <td><input type="text" name="captcha_input" value="" /> <%=request.getAttribute("ERROR") == null ? "" : request.getAttribute("ERROR")%></td> </tr> <tr> <td><input type="submit" value="提交" /></td> </tr> </table> </form> |
除了實現圖形驗證碼的生成和展示,我們還需要一個 Servlet 來驗證使用者的輸入。使用者輸入驗證的程式碼的核心,是使用在生成圖片時所使用的 service 物件,呼叫 JCaptcha 的輸入驗證方法(本示例為 validateResponseForID 方法),來判斷使用者輸入是否正確,清單 4 為輸入驗證程式碼片段。
清單 4. 驗證使用者輸入
validated = service.validateResponseForID( request.getSession(true).getId(), userCaptchaResponse).booleanValue(); |
完成上述程式碼工作後,我們還需要在 Web.xml 中設定好上面建立的兩個 Servlet,然後再部署到 Web 伺服器上,圖 1 是部署成功後的示例 1 首頁。
圖 1. 示例 1 的首頁
Sample1Index.jpg
至此,我們完成了第一個示例,該示例採用了 JCaptcha 提供的預設實現,下面我們將通過擴充套件使用 JCaptcha,來生成一個更為複雜的圖形驗證碼。
在實際專案中,我們可能需要使用更為複雜的圖形驗證碼,比如,加入帶干擾的圖形背景、更多的干擾點、自定義隨機字型檔及圖形字型等等,下面將基於示例 2 介紹如何使用 JCaptcha 生成更為複雜的圖形驗證碼。
正如介紹示例 1 時所提到的,我們可以通過實現 ImageCaptchaService 介面來建立我們自己所需要的 service 物件,清單 5 為示例 2 對介面 ImageCaptchaService 的實現,我們可以在該實現中,使用自己開發的圖形驗證碼生成引擎(SampleListImageCaptchaEngine)來生成更為複雜的圖形驗證碼。
清單 5. 示例 2 中 ImageCaptchaService 的實現
public class SampleImageCaptchaService extends AbstractManageableImageCaptchaService implements ImageCaptchaService { private static SampleImageCaptchaService instance; public static SampleImageCaptchaService getInstance() { if (instance == null) { //use customized engine ListImageCaptchaEngine engine = new SampleListImageCaptchaEngine(); instance = new SampleImageCaptchaService( new FastHashMapCaptchaStore(), engine, 180, 100000, 75000); } return instance; } public SampleImageCaptchaService(CaptchaStore captchaStore, CaptchaEngine captchaEngine, int minGuarantedStorageDelayInSeconds, int maxCaptchaStoreSize, int captchaStoreLoadBeforeGarbageCollection) { super(captchaStore, captchaEngine, minGuarantedStorageDelayInSeconds, maxCaptchaStoreSize, captchaStoreLoadBeforeGarbageCollection); } } |
清單 5 中的 FastHashMapCaptchaStore 用於存放生成的驗證碼字元,FastHashMapCaptchaStore 基本可以滿足絕大多數專案需求,我們通常不需要建立自己的類來實現它的功能;SampleListImageCaptchaEngine 則是擴充套件的核心,該類是 ImageCaptchaEngine 的一個實現,在該類中,我們可以設定隨機字型檔、生成的字型和大小、字元數、背景圖片以及干擾點等等。清單 6 為 SampleListImageCaptchaEngine 程式碼片段。
清單 6. SampleListImageCaptchaEngine 程式碼片段
//create text parser TextPaster randomPaster = new DecoratedRandomTextPaster(new Integer(8), new Integer(10), new SingleColorGenerator(Color.BLACK), new TextDecorator[] { new BaffleTextDecorator(new Integer(1), Color.WHITE) }); //create image captcha factory ImageCaptchaFactory factory = new GimpyFactory( new RandomWordGenerator("abcdefghijklmnopqrstuvwxyz"), new ComposedWordToImage(new TwistedRandomFontGenerator(new Integer(34), new Integer(40)), new FunkyBackgroundGenerator(new Integer( 260), new Integer(70)), randomPaster)); ImageCaptchaFactory characterFactory[] = { factory}; this.addFactories(characterFactory); |
在清單 6 中,DecoratedRandomTextPaster 的第一個引數用於設定驗證碼最少字元數,第二個引數為最多的字元數,第三個引數 SingleColorGenerator 為字型顏色,這裡為黑色,TextDecorator 為干擾設定,這裡是一個字元一個干擾點,並且干擾點為白色。
在 ImageCaptchaFactory 中,第一個引數設定了隨機字型檔,這裡為英文字母,在第二個引數中,TwistedRandomFontGenerator 設定了生成的字元字型,最小 34,最大為 40,FunkyBackgroundGenerator 則用於生成干擾背景,除了設定字型大小外,還需要設定生成的圖片大小,示例 2 為 260*70 畫素。圖 2 為示例 2 的首頁截圖。
圖 2. 示例 2 的首頁
Sample2Index.jpg
可以說 ImageCaptchaEngine 的不同實現,決定了圖形驗證碼的不同樣式,JCaptcha 目前提供了多種 ImageCaptchaEngine 的實現,這些實現提供了多種不同的圖形驗證碼樣式,當然,我們也可以自己實現 TextPaster 及 TextDecorator 等,進而再繼承實現 ImageCaptchaEngine,從而實現自己所期望的效果。圖 3 為 JCaptcha 官方網站提供的部分 ImageCaptchaEngine 的實現截圖,更多樣式,請參見 官方網站。
圖 3. JCaptcha 官方圖形驗證碼示例
JCaptchaSample.jpg
由於某些專案需要支援盲人使用,而盲人無法看到圖形驗證碼,這時,我們就需要同時提供聲音版的驗證碼。JCaptcha 同時支援聲音版驗證碼,但預設實現並不支援生成的聲音和圖形驗證碼中的字元一致,這裡就需要通過一定的擴充套件定製,才能保證聲音和圖形驗證碼的內容一致,下面首先介紹如何生成聲音驗證碼,然後介紹如何擴充套件定製,才能保證聲音和圖形驗證碼的內容的一致。
JCaptcha 使用了 FreeTTS 來開發聲音驗證碼,FreeTTS 是一個採用 Java 編寫的語音合成專案,它基於 Flite 專案編寫,Flite 專案是一個由卡內基梅隆大學開發的小型語音合成引擎,其又源於愛丁堡大學的 Festival 語音合成系統和卡內基梅隆大學的 FestVox 專案。本文的示例使用了 FreeTTS 1.2.2,該版本的有如下幾個方面的功能:
- 一個語音合成引擎
-
支援多種聲音
- 1 個 8khz,多音位,男性美國英語發音
- 1 個 16khz,多音位,男性美國英語發音
- 1 個 16khz 有限聲音域的男性美國英語發音
- 支援從 FestVox 匯入聲音(僅支援美國英語)
- 一定程度上支援從 FestVox 中匯入 CMU ARCTIC 聲音
-
支援 MBROLA 聲音(需另外下載該功能包)
- 1 個 16khz 女性美國英語發音
- 2 個 16khz 男性美國英語發音
- 部分支援 JSAPI 1.0
為了使用 FreeTTS,JCaptcha 還另外提供了一個 Jar 包用於和 FreeTTS 的整合,所以在執行過程中,除了需要引入 FreeTTS 自帶的 Jar 包,還需要包括 JCaptcha 提供的和 FreeTTS 整合的包,在示例 3 和 4 中,使用瞭如下的包:
- jcaptcha-extension-sound-freetts-1.0.jar:用於和 FreeTTS 的整合
- jcaptcha-1.0-all.jar: JCaptcha 核心包
- freetts.jar:FreeTTS 核心包
- en_us.jar:用於 FreeTTS
- commons-logging-1.1.1.jar:用於 JCaptcha
- commons-collections-3.2.jar:用於 JCaptcha
- cmutimelex.jar:用於 FreeTTS
- cmulex.jar:用於 FreeTTS
- cmudict04.jar:用於 FreeTTS
- cmu_us_kal.jar:用於 FreeTTS
- cmu_time_awb.jar:用於 FreeTTS
同 ImageCaptchaEngine 一樣,JCaptcha 同時提供了 SoundCaptchaEngine,所以整個聲音驗證碼的核心是建立 SoundCaptchaEngine 的實現,當然 JCaptcha 也提供了一些預設的實現,比如 DefaultSoundCaptchaEngine 以及 SpellerSoundCaptchaEngine 等等,為了考慮能夠支援生成和圖形驗證碼相同的字元,示例 3 採用繼承抽象類 ListSoundCaptchaEngine 的方式,來建立自己的實現 SampleListSoundCaptchaEngine。清單 7 為 SampleListSoundCaptchaEngine 程式碼片段。
清單 7. SampleListSoundCaptchaEngine 程式碼片段
public class SampleListSoundCaptchaEngine extends ListSoundCaptchaEngine { private static String voiceName = "kevin16"; private static String voicePackage = "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory"; protected void buildInitialFactories() { //create word generator WordGenerator wordGenerator = new RandomWordGenerator("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); //create decorator SpellerWordDecorator decorator = new SpellerWordDecorator(", "); //create sound factory SoundCaptchaFactory soundFactory[] = { new SpellerSoundFactory( wordGenerator, new FreeTTSWordToSound(new FreeTTSSoundConfigurator(voiceName, voicePackage, 1.0f, 100, 100), 4, 10), decorator) }; this.setFactories(soundFactory); } } |
同開發圖形驗證碼一樣,這裡也需要建立 SoundCaptchaService 的實現,實現方式與 ImageCaptchaService 的實現類似,示例 3 的實現類為 SampleSoundCaptchaService,這裡不做敘述,讀者可以參見附帶的示例原始碼。
和 ImageCaptchaService 的實現不同的是,這裡不能採用單例的方式來獲取 SoundCaptchaService 的實現,否則不能多次為同一 Session ID 生成多個聲音驗證碼檔案。另外,在使用者不重新整理頁面,而重複點選聲音驗證碼圖示時,我們需要提供同一段聲音,因此,我們可以將 SoundCaptchaService 的實現物件以及所生成的位元組碼流放入到 session 中,清單 7 為 SoundCaptchaServlet 程式碼片段。
清單 8. SoundCaptchaServlet 程式碼片段
httpServletResponse.setContentType("audio/x-wav"); SoundCaptchaService service = null; if ( httpServletRequest.getSession().getAttribute("soundService") != null) { service = (SoundCaptchaService) httpServletRequest .getSession().getAttribute("soundService"); } else { service = new SampleSoundCaptchaService(); } // get AudioInputStream using session ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); //get from the session if already existed, otherwise, create new one if (httpServletRequest.getSession().getAttribute("stream") == null) { AudioInputStream audioInputStream = service.getSoundChallengeForID( httpServletRequest.getSession().getId(), httpServletRequest.getLocale()); AudioSystem.write(audioInputStream, javax.sound.sampled.AudioFileFormat.Type.WAVE, byteOutputStream); } else { byteOutputStream = (ByteArrayOutputStream)httpServletRequest.getSession().getAttribute("stream"); } // output to servlet ServletOutputStream servletOutputStream = httpServletResponse.getOutputStream(); servletOutputStream.write(byteOutputStream.toByteArray()); // save the service object to session, will use it for validation // purpose httpServletRequest.getSession().setAttribute("soundService", service); httpServletRequest.getSession().setAttribute("stream", byteOutputStream); // output to servlet response stream try { servletOutputStream.flush(); } finally { servletOutputStream.close(); } |
為了方便使用者使用,我們需要在頁面上放置一個圖示,當焦點落在圖示上(考慮到盲人可能使用鍵盤 Tab 鍵來切換焦點),觸發 onFocus 事件來呼叫 JavaScript 方法顯示 embed 標籤,從而呼叫上面生成聲音驗證碼的 Servlet。圖 4 為示例 3 首頁截圖。
圖 4. 示例 3 執行頁面截圖
Sample3Index.jpg
當聲音驗證碼圖示在已經獲取焦點,並朗讀後,使用者可能多次重複讓該圖示獲取焦點以便多次收聽,這時,JavaScript 方法會被多次觸發,如果不做處理,其將多次請求 Servlet,以致生成不同的聲音檔案,本示例採用了前一個小節所介紹的快取 SoundCaptchaService 物件和位元組碼流的方法來解決這個問題,以保證多次能收聽到同一段聲音。當然,也可以採用在 URL 後面加一個隨機 token 的方式,來判斷是否重複提交。清單 8 為示例 3 首頁程式碼片段。
清單 9. 示例 3 index.jsp 程式碼片段
<% request.getSession().removeAttribute("soundService"); request.getSession().removeAttribute("stream"); %> <html> <head> <script type="text/javascript"> function playSoundCaptcha() { var wavURL = '<%= request.getContextPath() %>'+'/SoundCaptchaServlet'; var embedAudioPlayer = "<EMBED SRC='" + wavURL + "' HIDDEN='true' AUTOSTART='true' />"; |-------10--------20--------30--------40--------50--------60--------70--------80--------9| |-------- XML error: The previous line is longer than the max of 90 characters ---------| var wavArea = document.getElementById("wavArea"); wavArea.innerHTML = embedAudioPlayer; } </script> </head> <form action="CaptchaValidationServlet" method="post"> <table> <tr> <td colspan="2"><img src="ImageCaptchaServlet" /></td> </tr> <tr> <td> 請輸入您所看到的字元 :</td> <td><input type="text" name="captcha_input" value="" /> <a href="#" onFocus="playSoundCaptcha()"> <img src="image/wheelchair.jpg" height="18px" width="18px" alt=""></a><%=request.getAttribute("ERROR") == null ? "" : request .getAttribute("ERROR")%></td> </tr> <tr> <td><input type="submit" value="提交" /></td> </tr> <div id="wavArea" style="display:none"> </div> </table> </form> |
可以看到,我們採用了不在頁面顯示的 embed 標籤來呼叫 Servlet 以獲取聲音流,然後自動播放。在每次頁面重新整理的時候,還需要將 Session 中的 SoundCaptchaService 的實現物件以及音訊流刪除,以便頁面重新整理時,重新生成新的聲音驗證碼。
後臺用來驗證使用者輸入的邏輯和圖形版的驗證方式相似,這裡不做介紹,具體參見示例原始碼。需要注意的是,由於示例 3 生成的聲音驗證碼中的字元和圖形版的字元並不一致,在後臺驗證的邏輯中,只需要使用者輸入等於聲音驗證碼或圖形驗證碼的字元,即可認為使用者輸入正確。下面將介紹如何才能使聲音版和圖形版中的字元保持一致。
JCaptcha 並沒有提供很直觀的方式,來保證聲音驗證碼和圖形驗證碼中的字元一致,這就需要我們瞭解 JCaptcha 的實現,並能夠通過繼承的方式來擴充套件定製 JCaptcha,從而實現聲音和圖形驗證碼字元的一致。
由於圖形驗證碼會先於聲音驗證碼生成,所以,我們第一步就是需要獲取圖形驗證碼所生成的字串,然後是利用所獲取的字串來生成聲音驗證碼。
在以上示例中,雖然我們在實現 ImageCaptchaEngine 和 SoundCaptchaEngine 的時候,可以設定隨機數生成類,比如 RandomWordGenerator 等,但是即使聲音版和圖形版採用同一個隨機數生成物件,也不能保證會生成同一個字元,因為它們僅僅是設定一個隨機字型檔,而字元則是每次隨機生成。因而,我們並不能通過使用同樣的隨機數生成物件來生成同樣的隨機數,只能通過考慮使用圖形版生成的字元來生成聲音驗證碼,才能保持兩者的一致。
在建立 ImageCaptchaEngine 的實現時,我們需要提供一個 ImageCaptchaFactory,實際上,我們可以通過使用繼承實現 JCaptcha 已有 ImageCaptchaFactory 的實現,來獲取生成的隨機數。清單 9 是示例 4 中繼承了 GimpyFactory 的程式碼片段。
清單 9. SampleGimpyFactory 程式碼片段
public class SampleGimpyFactory extends GimpyFactory { …… public ImageCaptcha getImageCaptcha(Locale locale) { //length Integer wordLength = getRandomLength(); String word = getWordGenerator().getWord(wordLength, locale); if (this.wordBridge != null) { this.wordBridge.setGeneratedWord(word); } BufferedImage image = null; try { image = getWordToImage().getImage(word); } catch (Throwable e) { throw new CaptchaException(e); } ImageCaptcha captcha = new SampleGimpy(CaptchaQuestionHelper.getQuestion(locale, BUNDLE_QUESTION_KEY), image, word); return captcha; } } |
可以發現,通過使用上面的 SampleGimpyFactory 即可獲取圖形驗證碼的隨機數,所以我們可以將清單 6 中的 GimpyFactory 替換為 SampleGimpyFactory。
在獲取了生成的隨機數後,還需考慮如何將該隨機數傳遞給生成聲音驗證碼的程式碼。考慮到我們在生成驗證碼時,都是基於同一個 Session ID 生成,那麼我們就可以將生成的隨機數放到 map 中,而 key 是 Session ID,那麼,在生成驗證碼字元後,我們就可以用 Session ID 取出該字串,並放到 Session 中,然後,在生成聲音驗證碼的程式碼中,就可以從 Session 中獲取隨機數。但是,並不是所有程式碼都可以很方便的獲取到 ID,所以,我們還需要對示例 2 的程式碼進行改造,以便能夠根據 ID 儲存隨機數。清單 10 為改造後的清單 5 中的類 SampleImageCaptchaService 的程式碼片段。
清單 10. SampleImageCaptchaService 程式碼片段
public class SampleImageCaptchaService extends AbstractManageableImageCaptchaService implements ImageCaptchaService { … .. @Override public BufferedImage getImageChallengeForID(String ID) throws CaptchaServiceException { BufferedImage image= super.getImageChallengeForID(ID); String generatedWord = ((SampleListImageCaptchaEngine) engine).getWordBridge() .getGeneratedWord(); WordMap.getWordsMap().put(ID, generatedWord); return image; } } |
如清單 10 所示,我們將生成的隨機數放到了一個 map 中,而 key 則是 ID,這裡也就是 SessionID,然後我們就可以在 ImageCaptchaServlet 獲取並將該隨機數放到 Session 中,如清單 11 所示。接下來便是如何利用該字元生成聲音驗證碼。
清單 11. ImageCaptchaServlet 程式碼片段
httpServletRequest.getSession().setAttribute( "generatedWord", WordMap.getWordsMap().get(httpServletRequest.getSession(true) .getId())); |
為了能夠使用指定的字串生成驗證碼,我們需要對示例 3 中的程式碼做一定的修改。這裡,示例 4 通過繼承 SpellerSoundFactory 實現了一個擴充套件的 SoundCaptchaFactory,清單 12 為程式碼片段。
清單 12. SampleSpellerSoundFactory 程式碼片段
public class SampleSpellerSoundFactory extends SpellerSoundFactory { private String word; …… @Override public SoundCaptcha getSoundCaptcha() { return getSoundCaptcha(Locale.getDefault()); } @Override public SoundCaptcha getSoundCaptcha(Locale locale) { String soundWord = ""; if (this.word != null && !this.word.equals("")) { soundWord = this.word; } else { soundWord = this.wordGenerator.getWord(getRandomLength(), locale); } AudioInputStream sound = this.word2Sound.getSound(wordDecorator .decorateWord(soundWord), locale); SoundCaptcha soundCaptcha = new SpellerSound(getQuestion(locale), sound, word); return soundCaptcha; } } |
根據清單 11 中的程式碼,如果字串能夠正確的傳進來,這個 SampleSpellerSoundFactory 將可以根據該字串生成聲音驗證碼。
相應的,清單 7 中的 SampleListSoundCaptchaEngine 需要做如清單 13 所示的修改。
清單 13. SampleListSoundCaptchaEngine 程式碼
public class SampleListSoundCaptchaEngine extends ListSoundCaptchaEngine { private String word; private static String voiceName = "kevin16"; private static String voicePackage = "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory"; protected void buildInitialFactories() { WordGenerator wordGenerator = new RandomWordGenerator("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); SpellerWordDecorator decorator = new SpellerWordDecorator(", "); SoundCaptchaFactory soundFactory[] = { new SampleSpellerSoundFactory( wordGenerator, new FreeTTSWordToSound(new FreeTTSSoundConfigurator(voiceName, voicePackage, 1.0f, 100, 100), 4, 10), decorator, word) }; this.setFactories(soundFactory); } public SampleListSoundCaptchaEngine(String word) { this.word = word; buildInitialFactories(); } } |
需要注意的是,我們一定要有如清單 13 所示的帶引數的夠找函式,否則初始化時,該類會首先呼叫父類的建構函式,其父類會直接呼叫 buildInitialFactories 函式,而此時字串還沒有傳遞給父類。
接下來需要修改 SampleSoundCaptchaService,在該類中使用 SampleListSoundCaptchaEngine 並傳入隨機數引數。
清單 14. SampleSoundCaptchaService 程式碼片段
public class SampleSoundCaptchaService extends AbstractManageableSoundCaptchaService implements SoundCaptchaService { public SampleSoundCaptchaService(String word) { super(new FastHashMapCaptchaStore(), new SampleListSoundCaptchaEngine(word), 180, 100000, 75000); } …… } |
最後,我們只需要修改 SoundCaptchaServlet,先依據 Session ID 獲取生成的隨機數,然後呼叫清單 14 的 SampleSoundCaptchaService 生成聲音驗證碼,如清單 15 所示。
清單 15. SoundCaptchaServlet 程式碼片段
String word = ""; if (httpServletRequest .getSession().getAttribute("generatedWord") != null) { word = (String)httpServletRequest.getSession().getAttribute("generatedWord"); logger.info("Get generated word from the session, word=" + word); } service = new SampleSoundCaptchaService(word); |
至於後臺驗證邏輯,可以不做修改,也可以刪除原先用於驗證聲音驗證碼的程式碼。至此,聲音驗證碼的字元將與圖形驗證碼的字元保持一致。
本文先從一個簡單的示例入手,介紹瞭如何採用 JCaptcha 開發一個簡單的圖形驗證碼,然後介紹瞭如何通過擴充套件定製,實現更為複雜的圖形驗證碼,接下來介紹瞭如何採用 JCaptcha 開發聲音驗證碼,並在最後,介紹瞭如何擴充套件 JCaptcha 來保證圖形驗證碼和聲音驗證碼的內容一致。
相關文章
- 使用JCaptcha生成驗證碼APT
- 簡介
- Jira使用簡介 HP ALM使用簡介
- BookKeeper 介紹(1)--簡介
- Amphenol簡介
- Vagrant簡介
- PySimpleGUI 簡介GUI
- Protobuf簡介
- MyBatis 簡介MyBatis
- jango簡介Go
- cookie 簡介Cookie
- Session 簡介Session
- Cookie簡介Cookie
- Virgilio 簡介
- Django簡介Django
- ElasticSearch簡介Elasticsearch
- Javascript 簡介JavaScript
- Electron簡介
- Dubbo 簡介
- JavaScript簡介JavaScript
- CSS 簡介CSS
- 反射簡介反射
- JanusGraph -- 簡介
- CSS簡介CSS
- Bootstrap 簡介boot
- pwa簡介
- Apache簡介Apache
- JAVA簡介Java
- JUC簡介
- sass簡介
- NATS簡介
- Mybatis簡介MyBatis
- Zookeeper簡介
- Handlebars 簡介
- HTML簡介HTML
- jwt簡介JWT
- ThinkPHP 簡介PHP
- jQuery 簡介jQuery