驗證碼SimpleCaptcha

來源:互聯網
上載者:User

    想總結一下驗證碼(開源使用的驗證碼。當然,也可以自己去實現,不過有成熟的開源項目就用吧)的內容,然後看了幾個開源項目,發現SimpleCaptcha使用比較簡單,容易入手,就從它開始吧。

    接觸SimpleCaptcha

    1.下載 SimpleCaptcha

    2.將下載的JAR包添加到項目中

    3.配置Servlet

        可使用的Servlet:StickyCaptchaServlet、SimpleCaptchaServlet、AudioCaptchaServlet。

        StickyCaptchaServlet和SimpleCaptchaServlet產生圖片驗證碼,AudioCaptchaServlet產生語音驗證碼。

        StickyCaptchaServlet產生的驗證碼將儲存在session中,重新整理將不會重新建立。

        StickyCaptchaServlet are “sticky” to the user’s session: page reloads will render the same CAPTCHA instead of generating a new one.

    下面寫一個例子,簡單的配置servlet,頁面展示產生的驗證碼。

Servlet配置

 1     <servlet> 2         <servlet-name>StickyCaptcha</servlet-name> 3         <servlet-class>nl.captcha.servlet.StickyCaptchaServlet</servlet-class> 4     </servlet> 5     <servlet> 6         <servlet-name>SimpleCaptcha</servlet-name> 7         <servlet-class>nl.captcha.servlet.SimpleCaptchaServlet</servlet-class> 8     </servlet> 9     <servlet>10         <servlet-name>AudioCpatcha</servlet-name>11         <servlet-class>nl.captcha.servlet.AudioCaptchaServlet</servlet-class>12     </servlet>13 14     <servlet-mapping>15         <servlet-name>StickyCaptcha</servlet-name>16         <url-pattern>/sticky.png</url-pattern>17     </servlet-mapping>18     <servlet-mapping>19         <servlet-name>SimpleCaptcha</servlet-name>20         <url-pattern>/simple</url-pattern>21     </servlet-mapping>22     <servlet-mapping>23         <servlet-name>AudioCpatcha</servlet-name>24         <url-pattern>/audio</url-pattern>25     </servlet-mapping>

 

展示頁面

 1 <table> 2         <tr valign="top"> 3             <td>Sticky:</td> 4             <td><img src="http://localhost:8080/captcha/sticky.png" /> 5             </td> 6         </tr> 7         <tr valign="top"> 8             <td>Simple:</td> 9             <td><img src="http://localhost:8080/captcha/simple" />10             </td>11         </tr>12         <tr valign="top">13             <td>Audio:</td>14             <td><audio id="audio" src="http://localhost:8080/captcha/audio"15                     controls="controls"> 瀏覽器不支援&lt;audio&gt; </audio></td>16         </tr>17     </table>

 

    為什麼傳了三張?當然不是無聊,三張是依次重新整理後的。發現Sticky部分的驗證碼重新整理後也改變了,和上面的說明不一致啊。然後實驗在頁面上只放一個Sticky的驗證碼,重新整理的確沒改變。這是為什麼呢?觀察圖片發現每次重新整理收Sticky的內容都是上一次Simple的內容,恍然大悟......他們都往session裡存了內容,而且存的AttributeName都一樣,所以被覆蓋了。

    列印出session的內容後發現Sticky、Simple在session存入的名稱是simpleCaptcha(常量Captcha.NAME);Audio存入的名稱是audioCaptcha(常量AudioCaptcha.NAME),所以可以通過attributeName從session中取出對象並轉化成Captcha或AudioCaptcha,然後通過getAnswer方法擷取驗證碼的答案,或通過isCorrect(String answer)直接驗證傳入驗證碼是否在正確。

     使用中還發現StickyCaptchaServlet在初次載入時無法正常產生返回內容。在http://simplecaptcha.git.sourceforge.net/git/gitweb.cgi?p=simplecaptcha/simplecaptcha;a=commit;h=4c3a9eddfefabab6492c89f5c3887ca622ce4b0f上看到這個bug已經被修複,但是用過程中依舊出現。

    Sticky也不常用,按照目前的驗證碼習慣,採用的驗證碼都是重新整理頁面重建的方式。

    上面的例子中只是展示的基本的驗證碼的效果,沒有做驗證,下面實現驗證使用者輸入內容時候正確。

Form表單

 1 <form action="http://localhost:8080/captcha/answer.jsp" method="post"> 2         <table> 3             <tr valign="top"> 4                 <td>Simple:</td> 5                 <td><img src="http://localhost:8080/captcha/simple" /> 6                 </td> 7                 <td><input type="text" name="simpleAnswer" /> 8                 </td> 9             </tr>10 11             <tr valign="top">12                 <td>Audio:</td>13                 <td><audio id="audio" src="http://localhost:8080/captcha/audio"14                         controls="controls"> 瀏覽器不支援&lt;audio&gt; </audio>15                 </td>16                 <td><input name="audioAnswer" />17                 </td>18             </tr>19         </table>20         <input type="submit" value="提交" />21     </form>

    接收並判斷驗證碼是否正確的JSP(蛋疼的JSP,在也不想用JSP了

驗證JSP

 1 <% 2         Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME); 3         AudioCaptcha audioCaptcha = (AudioCaptcha) session 4                 .getAttribute(AudioCaptcha.NAME); 5         if (captcha.getAnswer() 6                 .equals(request.getParameter("simpleAnswer"))) { 7     %> 8     <B> Simple:Correct!</B> 9     <br />10     <%11         } else {12     %>13     <B> Simple:Wrong!</B>14     <br />15     <%16         }17         if (captcha.isCorrect(request.getParameter("audioAnswer"))) {18     %>19     <B> Audio:Correct!</B>20     <%21         } else {22     %>23     <B> Audio:Wrong!</B>24     <%25         }26     %>

    Audio也比較蛋疼,目前也不屬於常用的,畢竟語音驗證應用起來要求用戶端必須有語音輸出,而且對使用者也是有要求啊,聽不大好的話......

---------------------------------------------------------------------------------------------------------------------------------

    上面使用了simplecaptcha包內建的Servlet,實現了簡單的驗證碼產生及驗證,下面開始拓展 simplecaptcha實現自訂的驗證碼。

    編寫Servlet接收驗證碼的請求,使用Captcha.build()產生驗證碼,將圖片內容寫到返迴流中,so easy......

產生驗證碼的方法

 1 @Override 2     protected void doPost(HttpServletRequest req, HttpServletResponse resp) 3             throws ServletException, IOException { 4         // 簡單的是設定圖片長寬,新增內容 5         Captcha captcha = new Captcha.Builder(120, 38).addText().build(); 6         resp.setContentType("image/jpeg"); 7         OutputStream os = resp.getOutputStream(); 8         ImageIO.write(captcha.getImage(), "JPEG", os); 9         req.getSession().setAttribute("checkCode", captcha.getAnswer());10     }

    上面的代碼將驗證碼的答案存放在session中,當使用者輸入驗證碼並提交後可將使用者輸入內容與session中的內容比較來驗證是否正確。

    在深入一點,限制驗證碼的內容,去除0、1、l、O等容易混淆的內容,限定字型,設定背景等等等等......

    addBackground()使用預設的BackgroundProducer添加背景,addBackground(BackgroundProducer)可以通過實現BackgroundProducer介面提供自己的背景產生器。

    addBorder()在圖片周圍繪製一個但像素寬的邊框。

    addNoise()、addNoise(NoiseProducer nProd)分別通過預設的和提供的NoiseProducer設定“噪音”。使用預設的將在圖片中加入橫線。

    gimp()、gimp(GimpyRenderer gimpy)通過預設的或者提供的GimpyRenderer去對圖片進行模糊。

    addText()使用預設的TextProducer建立驗證碼內容。

    addText(TextProducer txtProd)使用提供的TextProducer建立驗證碼內容。

    addText(TextProducer txtProd,WordRenderer wRenderer)使用提供的TextProducer建立驗證碼內容,使用提供的WordRenderer渲染內容。

    addText(WordRenderer wRenderer)使用預設的TextProducer建立驗證碼內容,使用提供的WordRenderer渲染內容。

 

    build()建立Captcha對象。

    給出兩個像樣點的效果吧,自訂TextProducer及WordRanderer。

EasyCharTextProducer

 1 public class EasyCharTextProducer implements TextProducer { 2  3     private static final char[] chars = { 'a', 'c', 'd', 'e', 'f', 'h', 'j', 4             'k', 'm', 'n', 'p', 'r', 's', 't', 'w', 'x', 'y', '3', '4', '5', 5             '7', '8' }; 6  7     private static final int lastChar = chars.length; 8  9     private int length;10 11     public EasyCharTextProducer() {12         this(5);13     }14 15     public EasyCharTextProducer(int length) {16         super();17         this.length = length;18     }19 20     public String getText() {21         Random random = new Random();22         StringBuilder sb = new StringBuilder(length);23         for (int i = 0; i < length; i++) {24             int r = random.nextInt(lastChar);25             sb.append(chars[r]);26         }27         return sb.toString();28     }29 30 }
FixedWordRenderer

 1 public class FixedWordRenderer implements WordRenderer { 2     // The text will be rendered 25%/5% of the image height/width from the X and 3     // Y axes 4     private static final double YOFFSET = 0.20; 5     private static final double XOFFSET = 0.15; 6     private static final int charDistance = 5; 7     private static final Color DEFAULT_COLOR = Color.BLACK; 8     private static final List<Font> DEFAULT_FONTS = new ArrayList<Font>(); 9 10     private final Color _color;11     private final List<Font> _fonts;12 13     static {14         DEFAULT_FONTS.add(new Font("Arial", Font.BOLD, 40));15         DEFAULT_FONTS.add(new Font("Courier", Font.BOLD, 40));16     }17 18     /**19      * Will render the characters in black and in either 40pt Arial or Courier.20      */21     public FixedWordRenderer() {22         this(DEFAULT_COLOR, DEFAULT_FONTS);23     }24 25     public FixedWordRenderer(Color color, List<Font> fonts) {26         _color = color != null ? color : DEFAULT_COLOR;27         _fonts = fonts != null ? fonts : DEFAULT_FONTS;28     }29 30     /**31      * Render a word onto a BufferedImage.32      * 33      * @param word34      *            The word to be rendered.35      * @param bi36      *            The BufferedImage onto which the word will be painted on to37      */38     public void render(String word, BufferedImage image) {39         Random random = new Random();40         Graphics2D g = image.createGraphics();41 42         RenderingHints hints = new RenderingHints(43                 RenderingHints.KEY_ANTIALIASING,44                 RenderingHints.VALUE_ANTIALIAS_ON);45         hints.add(new RenderingHints(RenderingHints.KEY_RENDERING,46                 RenderingHints.VALUE_RENDER_QUALITY));47         g.setRenderingHints(hints);48 49         g.setColor(_color);50         FontRenderContext frc = g.getFontRenderContext();51         int startPosX = (int) Math.round(image.getWidth() * XOFFSET);52         int startPosY = image.getHeight()53                 - (int) Math.round(image.getHeight() * YOFFSET);54         char[] wc = word.toCharArray();55         for (char element : wc) {56             char[] itchar = new char[] { element };57             int choiceFont = random.nextInt(_fonts.size());58             Font itFont = _fonts.get(choiceFont);59             g.setFont(itFont);60 61             GlyphVector gv = itFont.createGlyphVector(frc, itchar);62             double charWitdth = gv.getVisualBounds().getWidth();63 64             g.drawChars(itchar, 0, itchar.length, startPosX, startPosY);65             startPosX = startPosX + (int) charWitdth66                     + random.nextInt(charDistance) - 2;67         }68     }69 70 }

    建立Captcha的代碼及對應效果

1 Captcha captcha = new Captcha.Builder(120, 38)2                 .addText(new EasyCharTextProducer(4),3                         new FixedWordRenderer(Color.white, englishFonts))4                 .addNoise()5                 .addNoise(new CurvedLineNoiseProducer(Color.gray, 1.5f))6                 .addBorder().addBackground(new GradiatedBackgroundProducer()).build();

1 Captcha captcha = new Captcha.Builder(120, 38)2                 .addText(new EasyCharTextProducer(4),3                         new FixedWordRenderer(Color.white, englishFonts))4                 .gimp(new FishEyeGimpyRenderer()).addBorder().build();

    要更好的效果就需要去瞭解gimpy、noise、background等包下面提供的randerer、producer的效果以及自己去實現介面提供自己的randerer和producer,當然,審美很重要...... 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.