(六)play之yabe項目【驗證碼】

添加驗證碼功能html

在Application.java中添加一個action:captcha()java

Java代碼   收藏代碼
  1. /** 
  2.  * 添加驗證碼 
  3.  */  
  4. public static void captcha(String id) {  
  5.     //Images.Captcha繼承了InputStream,具有流的功能  
  6.     Images.Captcha captcha = Images.captcha();  
  7.     //向客戶端輸出流  
  8.     renderBinary(captcha);  
  9. }  

 修改routes文件,爲得到驗證碼添加新的路由緩存

 

Html代碼   收藏代碼
  1. GET     /captcha            Application.captcha  

 

 

訪問http://localhost:9000/captcha,便可顯示驗證碼,每次刷新都顯示不一樣的驗證碼安全



 

 

 

服務端與客戶端如何處理驗證碼cookie

驗證碼生成了,服務端如何對其進行校驗呢?session

首先,play是一個無狀態的框架,它不會去維護每一個客戶端的session狀態框架

session以cookie形式存儲的,可是cookie未加密,在客戶端可以獲取到captcha,不安全dom

說一千道一萬,要驗證都須要對客戶端顯示的驗證碼進行跟蹤才能實現,否則丟了關聯如何驗證?!post

 

解決辦法:ui

在服務端使用緩存來保存驗證碼,爲其生成一個ID,將此ID傳到客戶端

再由客戶端顯示驗證碼時傳回服務端,服務端拿到ID後保存驗證碼

同時,客戶端的form中增長一個hidden來保存ID

當提交表單時,經過這個ID就能找到當時生成的驗證碼,繼而驗證

 

集羣環境下,這個緩存中的驗證碼怎麼處理呢?

Server A 處理請求,生成驗證碼,同時保存ID,返回驗證碼

提交表單時,請求被分配給Server B 進行處理,Server B 的緩存裏沒有這個ID啊,怎麼辦?

 

共享緩存,好比,使用Redis做爲幾個Server共用的一個大緩存

 

改造Application的captcha(),將驗證碼captcha放到緩存中 

Java代碼   收藏代碼
  1. /** 
  2.  * 添加驗證碼 
  3.  * @param id 服務端緩存中存放的驗證碼的id(一個uuid) 
  4.  */  
  5. public static void captcha(String id) {  
  6.     //Images.Captcha繼承了InputStream,具有流的功能  
  7.     Images.Captcha captcha = Images.captcha();  
  8.       
  9.     //爲驗證碼指定顏色並返回驗證碼  
  10.     String code = captcha.getText("#E4EAFD");  
  11.       
  12.     //放到緩存中,緩存有效期10mn  mn分鐘?  
  13.     Cache.set(id, code, "10mn");  
  14.       
  15.     //向客戶端輸出流  
  16.     renderBinary(captcha);  
  17. }  

 

在顯示評論的窗體時,生成一個惟一的ID,返回到客戶端的頁面中

Java代碼   收藏代碼
  1. /** 
  2.  * 顯示詳細的博文評論 
  3.  */  
  4. public static void show(Long id) {  
  5.     Post post = Post.findById(id);  
  6.     //生成一個惟一的ID,做爲服務端保存驗證碼時的key  
  7.     String randomID = Codec.UUID();   
  8.     render(post, randomID);  
  9. }  

 

在show.html模板中顯示驗證碼時,傳入此ID

Html代碼   收藏代碼
  1. <!-- 顯示一個表單,用戶能夠添加評論 -->  
  2. <h3>Post a comment</h3>  
  3. #{form @Application.postComment(post.id)}  
  4.       
  5.     <!-- 在這裏顯示提交評論時出現的錯誤 -->  
  6.     #{ifErrors}  
  7.         <class="error">All fields are required!</p>  
  8.     #{/ifErrors}  
  9.       
  10.     <p>  
  11.         <label for="author">Your name:</label>  
  12.         <input type="text" name="author" id="author"/>  
  13.     </p>  
  14.     <p>  
  15.         <label for="content">Your comment:</label>  
  16.         <textarea name="content" id="content"></textarea>  
  17.     </p>  
  18.       
  19.     <!-- 驗證碼 -->  
  20.     <p>  
  21.         <label for="code">Please type the code below:</label>  
  22.         <img alt="captcha" src="@{Application.captcha(randomID)}">  
  23.         <br/>  
  24.         <input type="text" name="code" id="code" size="18" value=""/>  
  25.         <input type="hidden" name="id" value="${randomID}">  
  26.     </p>  
  27.       
  28.     <p>  
  29.         <input type="submit" value="submit your comment"/>          
  30.     </p>  
  31. #{/form}  

 

刷新頁面,點擊博文添加評論



 

 

 

服務端對驗證碼進行校驗

客戶端已經經過隱藏域保存了驗證碼的ID,提交表單後,服務端的postComment()接收到ID後就能進行驗證操做了!

讓postComment()接收ID並從緩存中取出驗證碼,進行校驗

此外,具體指定了@Required標明的字段爲空時,對應的提示信息

Java代碼   收藏代碼
  1. /** 
  2.     * 添加評論 
  3.     * 使用@Required註解,檢測author和content參數不能爲空 
  4.     *  
  5.     * @param code 客戶端輸入的驗證碼 
  6.     * @param randomID 服務端保存驗證碼時用的ID 
  7.     */  
  8.    public static void postComment(  
  9.                             Long postId,   
  10.                             @Required(message="Author is required") String author,   
  11.                             @Required(message="A comment is required") String content,  
  12.                             @Required(message="Please type the code below") String code,  
  13.                             String randomID) {  
  14.       
  15.     Post post = Post.findById(postId);  
  16.       
  17.     //驗證碼校驗,若是equals()返回false,則message()中的信息將傳遞到客戶端  
  18.     validation.equals(code, Cache.get(randomID)  
  19.             ).message("Invalid code,Please type it again!");  
  20.       
  21.     //錯誤檢測  
  22.     if(validation.hasErrors()) {  
  23.         //將post對象從新傳入模板中,不然新打開的show.html中的post爲null!!!  
  24.         render("Application/show.html",post);  
  25.     }  
  26.     //保存評論信息  
  27.     post.addComment(author, content);  
  28.       
  29.     //設置提交成功後的提示信息到flash做用域  
  30.     flash.success("Thanks for posting %s", author);  
  31.       
  32.     //從新顯示該篇博文即其評論  
  33.     show(postId);  
  34.    }  

 

修改show.html模板,若是驗證失敗,則顯示驗證失敗的提示信息

Html代碼   收藏代碼
  1. <!-- 顯示一個表單,用戶能夠添加評論 -->  
  2. <h3>Post a comment</h3>  
  3. #{form @Application.postComment(post.id)}  
  4.       
  5.     <!--   
  6.         這裏顯示提交評論時出現的錯誤  
  7.         因爲postComment()中已經使用@Required(message="xxx")聲明瞭錯誤提示信息  
  8.         因此,這裏只須要顯示第一個錯誤便可!  
  9.     -->  
  10.     #{ifErrors}  
  11.         <class="error">${errors[0]}</p>  
  12.     #{/ifErrors}  
  13.       
  14.     <p>  
  15.         <label for="author">Your name:</label>  
  16.         <input type="text" name="author" id="author"/>  
  17.     </p>  
  18.     <p>  
  19.         <label for="content">Your comment:</label>  
  20.         <textarea name="content" id="content"></textarea>  
  21.     </p>  
  22.       
  23.     <!-- 驗證碼 -->  
  24.     <p>  
  25.         <label for="code">Please type the code below:</label>  
  26.         <img alt="captcha" src="@{Application.captcha(randomID)}">  
  27.         <br/>  
  28.         <input type="text" name="code" id="code" size="18" value=""/>  
  29.         <input type="hidden" name="id" value="${randomID}">  
  30.     </p>  
  31.       
  32.     <p>  
  33.         <input type="submit" value="submit your comment"/>          
  34.     </p>  
  35. #{/form}  

 

 驗證錯誤的狀況下,爲了保持客戶端輸入的評論內容,在action中重傳客戶端輸入的內容

修改Application.postComment(),這裏有不少須要注意的地方!!!

Java代碼   收藏代碼
  1. /** 
  2.      * 添加評論 
  3.      * 使用@Required註解,檢測author和content參數不能爲空 
  4.      *  
  5.      * @param code 客戶端輸入的驗證碼 
  6.      * @param randomID 服務端保存驗證碼時用的ID 
  7.      */  
  8.     public static void postComment(  
  9.                                 Long postId,   
  10.                                 String author,   
  11.                                 @Required(message="A comment is required") String content,  
  12.                                 @Required(message="Please type the code below") String code,  
  13.                                 String randomID) {  
  14.           
  15.         System.out.println("Application.postComment()");  
  16.         Post post = Post.findById(postId);  
  17.           
  18.         //驗證碼校驗,若是equals()返回false,則message()中的信息將傳遞到客戶端  
  19.         Logger.info("提交評論,randomID="+randomID);  
  20.         Logger.info("提交評論,驗證碼="+code);  
  21.         validation.equals(code, Cache.get(randomID)  
  22.                 ).message("Invalid code,Please type it again!");  
  23.           
  24.         //錯誤檢測  
  25.         if(validation.hasErrors()) {  
  26.             /** 
  27.              * 將post對象從新傳入模板中,不然新打開的show.html中的post爲null!!! 
  28.              * 若是出現錯誤,則將客戶端輸入的評論內容從新返回到客戶端進行回顯。 
  29.              * 必須將randomID從新傳回到客戶端,否則客戶端的然的randomID將取不到值 
  30.              * 最後致使提價評論後,驗證碼的ID爲空,沒法進行驗證碼的校驗操做--老是校驗錯誤,這裏很關鍵! 
  31.              * 並且,這裏render("Application/show.html")直接調用模板,不會再調用show()進行驗證碼ID的生成 
  32.              * 因此,一個客戶端在未驗證成功以前,都將使用這個ID做爲服務端緩存的key進行存儲 
  33.             */  
  34.             render("Application/show.html",post,randomID,author,content);  
  35.         }  
  36.         //保存評論信息  
  37.         post.addComment(author, content);  
  38.           
  39.         //設置提交成功後的提示信息到flash做用域  
  40.         flash.success("Thanks for posting %s", author);  
  41.           
  42.         //清除指定驗證碼的緩存  
  43.         Cache.delete(randomID);  
  44.           
  45.         //從新顯示該篇博文即其評論  
  46.         show(postId);  
  47.     }  

 

 

 在show.html中,爲評論的2個輸入域增長value屬性,用來顯示回顯的內容

Html代碼   收藏代碼
  1. <p>  
  2.     <label for="author">Your name:</label>  
  3.     <!-- ${author}:回填數據 -->  
  4.     <input type="text" name="author" id="author" value="${author}"/>  
  5. </p>  
  6. <p>  
  7.     <label for="content">Your comment:</label>  
  8.     <!-- ${content}:回填數據 -->  
  9.     <textarea name="content" id="content">${content}</textarea>  
  10. </p>  

 

刷新頁面,從新評論



 

後臺校驗發現驗證碼錯誤,刷新show.html,回顯上一次輸入的評論並從新生成驗證碼



 

輸入正確的驗證碼,提交評論,成功!



 

輸入正確的驗證碼以後,評論提交成功!

 

 另外,如今對驗證碼的要求是,嚴格區分大小寫!

要實現IgnoreCase,也簡單,保存驗證碼到緩存的時候,校驗的時候作點手腳就好了!

相關文章
相關標籤/搜索