JCaptcha(Completely Automated Public Turing Test to Tell Computers and Humans Apart 的 Java 實作)是防止暴力破解、垃圾灌水的經典方案。SpringSide 3 Showcase 已內建整合範例,本文將其拆解為可直接落地的步驟,涵蓋 Spring Security 整合 Filter 與 非 Spring Security 場景的 AJAX 手動驗證 兩大模式。
WEB-INF/lib)jcaptcha-1.0.jar — 核心實作jcaptcha-api-1.0.jar — 介面定義imaging-01012005.jar — 提供 WaterFilter 等圖片處理類springside3-jee-3.1.5.jar — SpringSide 對 JCaptcha 的擴充(GMailEngine、JCaptchaFilter)<!-- JCaptcha 驗證碼服務 -->
<bean id="captchaService" class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService">
<property name="captchaEngine">
<bean class="org.springside.modules.security.jcaptcha.GMailEngine" />
</property>
<property name="minGuarantedStorageDelayInSeconds" value="600" />
</bean>
web.xml Filter 配置(順序關鍵)<!-- SpringSide JCaptcha Filter -->
<filter>
<filter-name>jcaptchaFilter</filter-name>
<filter-class>org.springside.modules.security.jcaptcha.JCaptchaFilter</filter-class>
<init-param>
<param-name>failureUrl</param-name>
<param-value>/login.action?error=2</param-value>
</init-param>
</filter>
<!-- 1. 驗證碼圖片產生 URL -->
<filter-mapping>
<filter-name>jcaptchaFilter</filter-name>
<url-pattern>/security/jcaptcha.jpg</url-pattern>
</filter-mapping>
<!-- 2. 登入表單處理 URL —— 必須在 springSecurityFilter 之前 -->
<filter-mapping>
<filter-name>jcaptchaFilter</filter-name>
<url-pattern>/j_spring_security_check</url-pattern>
</filter-mapping>
⚠️jcaptchaFilter對/j_spring_security_check的攔截必須在springSecurityFilterChain之前,否則 Spring Security 先處理登入邏輯,驗證碼檢查將失效。
<img id="captchaImage"
src="${ctx}/security/jcaptcha.jpg"
width="100" height="40" align="middle"
onclick="onImageClick(this);" />
(看不清請點擊圖片更換)
function onImageClick(o) {
o.src = "${ctx}/security/jcaptcha.jpg?update=" + Math.random();
}
適用於:用戶註冊、發文、API 介面等需在不跳轉頁面驗證的場景。
// 驗證 captchaImage
boolean flag = false;
try {
HttpServletRequest request = Struts2Utils.getRequest();
String captchaID = request.getSession().getId(); // JCaptcha 預設用 Session ID 作為 captchaId
String captchaValue = request.getParameter("captchaValue"); // 用戶輸入
ApplicationContext context = WebApplicationContextUtils
.getWebApplicationContext(Struts2Utils.getSession().getServletContext());
CaptchaService captchaService = (CaptchaService) context.getBean("captchaService");
flag = captchaService.validateResponseForID(captchaID, captchaValue);
} catch (Exception e) {
flag = false;
}
if (!flag) {
success = false;
result += "captcha_err.innerHTML='驗證碼輸入錯誤。';";
} else {
result += "captcha_err.innerHTML='';";
}
if (!success) {
result += "failed();";
Struts2Utils.renderHtml(result, "encoding:UTF-8");
}
| 類別 | 來源 | 用途 |
|---|---|---|
DefaultManageableImageCaptchaService | JCaptcha 核心 | 管理驗證碼生命週期(產生、儲存、驗證、清理) |
GMailEngine | SpringSide 擴充 | 模仿 Gmail 風格的圖片生成引擎(干擾線、扭曲字體、顏色變化) |
JCaptchaFilter | SpringSide 擴充 | 攔截 /security/jcaptcha.jpg 產圖、攔截登入 URL 驗證、失敗導向 failureUrl |
| 現象 | 原因 | 解決 |
|---|---|---|
| 驗證碼圖片不顯示 | Filter mapping 順序錯誤、imaging JAR 缺失 | 檢查 web.xml 順序、確認四個 JAR 皆在 classpath |
| 永遠驗證失敗 | Session ID 不一致(如跨域、Session 失效) | 確認前後端同一 Session;AJAX 請求攜帶 JSESSIONID Cookie |
| 圖片太難辨識 | GMailEngine 參數過激進 | 自訂 CaptchaEngine 繼承 ListImageCaptchaEngine 調整干擾強度 |
JCaptchaFilter,配置兩個 filter-mapping,順序在 Spring Security 之前。captchaService Bean,手動呼叫 validateResponseForID(sessionId, userInput)。GMailEngine 提供開箱即用的高強度驗證碼圖片,亦可自行實作 CaptchaEngine 客製化。