JCaptcha (Java CAPTCHA) 支援圖形/語音驗證碼,需三個 JAR:jcaptcha-2.0-all.jar、commons-collections-3.2.jar、commons-logging-1.1.1.jar。
<servlet> <servlet-name>jcaptcha</servlet-name> <servlet-class>com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet</servlet-class> </servlet> <servlet> <servlet-name>submit</servlet-name> <servlet-class>com.octo.captcha.module.servlet.image.sample.SubmitActionServlet</servlet-class> </servlet> <servlet-mapping><servlet-name>jcaptcha</servlet-name><url-pattern>/jcaptcha.jpg</url-pattern></servlet-mapping> <servlet-mapping><servlet-name>submit</servlet-name><url-pattern>/submit.action</url-pattern></servlet-mapping>
public class SubmitActionServlet extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String userCaptchaResponse = req.getParameter("japtcha");
boolean passed = SimpleImageCaptchaServlet.validateResponse(req, userCaptchaResponse);
resp.getWriter().write(passed ? "captcha passed" : "captcha failed");
resp.getWriter().write("<br/><a href='index.jsp'>Try again</a>");
}
}
<img src="jcaptcha.jpg" /> <input type="text" name="japtcha" /> <input type="submit" />
核心 KaptchaServlet 生成圖片並將驗證碼存入 Session (KAPTCHA_SESSION_KEY)。
<servlet> <servlet-name>Kaptcha</servlet-name> <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class> <init-param><param-name>kaptcha.border</param-name><param-value>yes</param-value></init-param> <init-param><param-name>kaptcha.border.color</param-name><param-value>black</param-value></init-param> <init-param><param-name>kaptcha.image.width</param-name><param-value>120</param-value></init-param> <init-param><param-name>kaptcha.image.height</param-name><param-value>40</param-value></init-param> <init-param><param-name>kaptcha.textproducer.font.names</param-name><param-value>Arial, Courier</param-value></init-param> <init-param><param-name>kaptcha.textproducer.font.size</param-name><param-value>30</param-value></init-param> <init-param><param-name>kaptcha.textproducer.font.color</param-name><param-value>black</param-value></init-param> <init-param><param-name>kaptcha.textproducer.char.length</param-name><param-value>4</param-value></init-param> <init-param><param-name>kaptcha.noise.impl</param-name><param-value>com.google.code.kaptcha.impl.DefaultNoise</param-value></init-param> <init-param><param-name>kaptcha.obscurificator.impl</param-name><param-value>com.google.code.kaptcha.impl.WaterRipple</param-value></init-param> <init-param><param-name>kaptcha.session.key</param-name><param-value>KAPTCHA_SESSION_KEY</param-value></init-param> </servlet> <servlet-mapping><servlet-name>Kaptcha</servlet-name><url-pattern>/randomcode.jpg</url-pattern></servlet-mapping>
<img id="captcha" src="randomcode.jpg" onclick="this.src='randomcode.jpg?t='+new Date().getTime()" />
String k = (String) session.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
String input = request.getParameter("r");
if (k.equals(input)) out.print("true");
繼承 DefaultTextCreator 並覆寫 getText():
public class ChineseText extends Configurable implements TextProducer {
public String getText() {
int len = getConfig().getTextProducerCharLength();
String[] chs = {"我","愛","扎","瓦","和","賣","塞","扣"};
Random r = new Random();
StringBuilder sb = new StringBuilder();
for (int i=0; i<len; i++) sb.append(chs[r.nextInt(chs.length)]);
return sb.toString();
}
}
web.xml 指定:<param-name>kaptcha.textproducer.impl</param-name><param-value>ChineseText</param-value>
繼承 KaptchaServlet 覆寫 doGet():
public class KaptchaServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String capText = kaptchaProducer.createText(); // 如 "3+5=?"
String[] parts = capText.split("[+=]");
int result = Integer.parseInt(parts[0]) + Integer.parseInt(parts[1]);
req.getSession().setAttribute(sessionKeyValue, String.valueOf(result));
BufferedImage bi = kaptchaProducer.createImage(capText);
ImageIO.write(bi, "jpg", resp.getOutputStream());
}
}
web.xml 指定自訂 Servlet 類。
定義:結合「你知道的」(密碼)+「你擁有的」(手機/Token/生物特徵)。
核心優勢:動態參數(時間/事件)+ 密鑰 算法生成一次性密碼,不可預測、不可重放。
從簡單繪圖到 JCaptcha/Kaptcha 組件,再到中文/算術客製化,驗證碼形式日益豐富。但單靠驗證碼不足,生產環境應採用雙因子認證、風控引擎、行為分析等多層防護體系。