驗證碼?
就是防止機器人送出表單的驗證圖片,這是目前辨識真假人最常見的作法。驗證流程
- 使用 <img src="..."/> 產生驗證圖片,注意 src 是指向 Java Servlet,用以動態產生驗驗證圖片,而不是一張靜態的圖片。
- 在 web.xml 設定產生驗證圖片的 <servlet/> 與 <servlet-mapping/>
- 撰寫 Java Servlet,每次呼叫 Java Servlet 時,除產生驗證圖片塞到 response 以外,還要將答案寫到 session 裡,供事後比對。
- Form submit 到後台時,左手拿使用者輸入的驗證碼,右手拿 session 裡的答案,兩相做比較即可。
貼心的功能
- 在網頁上加上「重新產生驗證碼」功能,只要使用 Javascript 讓 img 重新載入圖片就可以,若擔心 cache,可以每次重新整理時在網址上加上時間戳記。
- 在網頁輸入時,使用 Javascript 將輸入的值自動轉大寫,當然驗證值一開始就得是大寫,這可以減低傷害使用者的耐心。
- 送到後台比對時,先將兩邊(使用者輸入與從 session 取得的答案)值的英文字母「歐」都換成數字「零」,以及英文字母「唉」換成數字「壹」,這是避免 O / 0 與 I / 1 的誤會。
下載 SimpleCaptcha
請到官網下載,目前版本是 1.2.1,Maven repository 上的還是 1.1.1,Maven Repository 上還有個版本超前官網的 1.2.2 的同名 library,別誤會了,這可是強國人製作的,原因不明。
然後在 web.xml 加上以下設定,重起湯姆貓,就可以在 http://localhost/stickyImg 看到驗證圖片了,重新整理也可以看到每次驗證碼都不同。
然後在 web.xml 加上以下設定,重起湯姆貓,就可以在 http://localhost/stickyImg 看到驗證圖片了,重新整理也可以看到每次驗證碼都不同。
<servlet> <servlet-name>StickyCaptcha</servlet-name> <servlet-class>nl.captcha.servlet.StickyCaptchaServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>StickyCaptcha</servlet-name> <url-pattern>/stickyImg</url-pattern> </servlet-mapping>很簡單?但是預設的文字/圖片真的有點不美觀。
客制 SimpleCaptcha
就是改寫 nl.captcha.servlet.SimpleCaptchaServlet,客制文字字型與大小,以及背景圖。public class EasySimpleCaptchaServlet extends SimpleCaptchaServlet { // 以下四個參數相互影響,圖大則字型大,字多字大則圖大 private int width = 60; private int height = 25; private int length = 4; private int fontSize = 20; // 背景圖,放在 classpath 裡 private String backgroundImg = "CaptchaBackground.jpg"; @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 建立 Captcha 物件 Captcha captcha = this.buildCaptcha(); // 將 Captcha 物件裡的圖片寫入 HttpServletResponse CaptchaServletUtil.writeImage(resp, captcha.getImage()); // form submit 後再用 Captcha.NAME 取得 Captcha 物件,然後呼叫 getAnswer() 來比值 req.getSession().setAttribute(Captcha.NAME, captcha); } private Captcha buildCaptcha() { // 文字顏色 List<Color> colorList = new ArrayList<Color>(); colorList.add(Color.BLACK); // 文字字型 List<Font> fontList = new ArrayList<Font>(); fontList.add(new Font(Font.SERIF, Font.BOLD, this.fontSize)); // 設定長寬、設定文字產生器、設定文字顏色與字型、設定背景 Captcha captcha = new Captcha.Builder(this.width, this.height).addText(new EasyTextProducer(this.length), new DefaultWordRenderer(colorList, fontList)).addBackground(new EasyBackgroundProducer()).build(); return captcha; } /** * 設定背景 - 以一張圖片作為背景,並隨機使用背景圖片的某一位置 */ private final class EasyBackgroundProducer implements BackgroundProducer { /** * 不知道作用,不用改 */ @Override public BufferedImage addBackground(BufferedImage bi) { int width = bi.getWidth(); int height = bi.getHeight(); return this.getBackground(width, height); } @Override public BufferedImage getBackground(int width, int height) { try { // 讀入背景圖 Image image = ImageIO.read(this.getClass().getClassLoader().getResourceAsStream(backgroundImg)); BufferedImage buffered = (BufferedImage) image; // 可用的 x 與 y 值 int x = buffered.getWidth() - width; int y = buffered.getHeight() - height; // 隨機產生 x = (int) (Math.random() * x); y = (int) (Math.random() * y); // 防呆 x = Math.max(x, 0); y = Math.max(y, 0); // 切出需要的背景圖 return buffered.getSubimage(x, y, width, height); } catch (IOException e) { e.printStackTrace(); } // 若出意外,挺多沒有背景圖 return null; } } /** * 文字產生器 - 只使用 數字與大寫英文字母 */ private final class EasyTextProducer implements TextProducer { private int length; public EasyTextProducer(int length) { // 設定驗證碼長度 this.length = length; } @Override public String getText() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < this.length; i++) { int n = (int) (Math.random() * 36); if (n <= 9) { sb.append(String.valueOf(n)); } else { n -= 10; n += 97; sb.append((char) n); } } return sb.toString().toUpperCase(); } } public static void main(String[] args) throws IOException { Captcha captcha = new EasySimpleCaptchaServlet().buildCaptcha(); File outputfile = new File("image_" + new Date().getTime() + ".jpg"); ImageIO.write(captcha.getImage(), "jpg", outputfile); } }不解釋,看起來好多了。
// 重新產生驗證圖片 $('#stickyImg').attr('src', 'stickyImg?_v=' + new Date().getTime()); // 自動轉大寫 $('input[name=verifyCode]').keyup(function(){ $(this).val($(this).val().toUpperCase()); });---
---
---
沒有留言:
張貼留言