jcaptcha组件小小改造解决Invalid ID, could not validate une

本文介绍如何解决使用Jcaptcha组件时遇到的Ajax校验验证码异常问题,通过自定义CaptchaService实现类并修改validateResponseForID方法,避免在验证失败时立即移除session对应的验证码信息,从而满足Ajax校验的需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

jcaptcha是一款很好的java实现的验证码组件,官方地址:http://jcaptcha.sourceforge.net/
在使用jcaptcha过程中,我相信很多人在用ajax校验验证码的时候都遇到过下面这样的异常:

Invalid ID, could not validate unexisting or already validated captcha

其实分析jcaptcha源码不难得知,这个异常是因为AbstractCaptchaService中的validateResponseForID方法逻辑在捣乱,看看源码:

public Boolean validateResponseForID(String ID, Object response)
    throws CaptchaServiceException
  {
    if (!this.store.hasCaptcha(ID)) {
      throw new CaptchaServiceException("Invalid ID, could not validate unexisting or already validated captcha");
    }
    Boolean valid = this.store.getCaptcha(ID).validateResponse(response);
    this.store.removeCaptcha(ID);
    return valid;
  }

其中有句this.store.removeCaptcha(ID);,就是这句代码在捣乱。这句代码的意思就是说,不管什么时候,一档执行了validateResponseForID方法,就会把原来的那个session从store当中移除,那么这样,如果你采用的是ajax提交校验的话,验证码生成逻辑没有重新执行,就会报上面的Invalid ID异常,如果是校验失败就重新刷新页面重新生成应该就问题,没有验证是不是这样,道理就是这么个道理了……
那么为了满足ajax校验,我们做点稍微的改造:
首先我们如果采用的GenericManageableCaptchaService作为CaptchaService实现类,我就自定义一个Service来继承GenericManageableCaptchaService,代码如下:

public class CustomGenericManageableCaptchaService extends
		GenericManageableCaptchaService {

	/**
	 * The constructor method of class CustomManageableCaptchaService.java .
	 * 
	 * @param captchaEngine
	 * @param minGuarantedStorageDelayInSeconds
	 * @param maxCaptchaStoreSize
	 * @param captchaStoreLoadBeforeGarbageCollection
	 */
	public CustomGenericManageableCaptchaService(CaptchaEngine captchaEngine,
			int minGuarantedStorageDelayInSeconds, int maxCaptchaStoreSize,
			int captchaStoreLoadBeforeGarbageCollection) {
		super(captchaEngine, minGuarantedStorageDelayInSeconds,
				maxCaptchaStoreSize, captchaStoreLoadBeforeGarbageCollection);
	}

	/**
	 * The constructor method of class CustomManageableCaptchaService.java .
	 * 
	 * @param captchaStore
	 * @param captchaEngine
	 * @param minGuarantedStorageDelayInSeconds
	 * @param maxCaptchaStoreSize
	 * @param captchaStoreLoadBeforeGarbageCollection
	 */
	public CustomGenericManageableCaptchaService(CaptchaStore captchaStore,
			CaptchaEngine captchaEngine, int minGuarantedStorageDelayInSeconds,
			int maxCaptchaStoreSize, int captchaStoreLoadBeforeGarbageCollection) {
		super(captchaStore, captchaEngine, minGuarantedStorageDelayInSeconds,
				maxCaptchaStoreSize, captchaStoreLoadBeforeGarbageCollection);
	}

	/**
	 * 修改验证码校验逻辑,默认的是执行了该方法后,就把sessionid从store当中移除<br/>
	 * 然而在ajax校验的时候,如果第一次验证失败,第二次还得重新刷新验证码,这种逻辑不合理<br/>
	 * 现在修改逻辑,只有校验通过以后,才移除sessionid。 Method Name:validateResponseForID .
	 * 
	 * @param ID
	 * @param response
	 * @return
	 * @throws CaptchaServiceException
	 *             the return type:Boolean
	 */
	@Override
	public Boolean validateResponseForID(String ID, Object response)
			throws CaptchaServiceException {
		if (!this.store.hasCaptcha(ID)) {
			throw new CaptchaServiceException(
					"Invalid ID, could not validate unexisting or already validated captcha");
		}
		Boolean valid = this.store.getCaptcha(ID).validateResponse(response);
		//源码的这一句是没被注释的,这里我们注释掉,在下面暴露一个方法给我们自己来移除sessionId
		//this.store.removeCaptcha(ID);
		return valid;
	}
	
	/**
	 * 移除session绑定的验证码信息.
	 * Method Name:removeCaptcha .
	 * @param sessionId
	 * the return type:void
	 */
	public void removeCaptcha(String sessionId){
		if(sessionId!=null && this.store.hasCaptcha(sessionId)){
			this.store.removeCaptcha(sessionId);
		}
	}
}

从代码中我们可以看到两个改造:
1、重写了validateResponseForID方法,只是注释了一行代码;
2、增加了一个方法removeCaptcha,用来让我们手工移除session对应的验证码信息

然后就把bean对应的实现类指定到我们的自定义实现上,如下:

<bean id="captchaService" class="com.cmcc.ict.iplanning.captcha.CustomGenericManageableCaptchaService">
	<constructor-arg index="0"><ref bean="imageEngine"/></constructor-arg>
	<constructor-arg index="1"><value>180</value></constructor-arg>
	<constructor-arg index="2"><value>180000</value></constructor-arg>
	<constructor-arg index="3"><value>75000</value></constructor-arg>
</bean>

最后就是在你的业务逻辑里面手动调用removeCapthca()方法了,例如:

try {

  currentUser.login(token);

  ....

  //成功以后移除验证码信息

  captchaService.removeCaptcha(sessionId);

} catch (UnknownAccountException uae) {

  ....

} catch (IncorrectCredentialsException ice) {

  ....

} catch (LockedAccountException lae) {

  ....

} catch (ExcessiveAttemptsException eae) {

  ....

} catch (AuthenticationException ae) {

  ....

}





转载于:https://my.oschina.net/chainlong/blog/192014

### 解决 'Could not write JSON: Invalid ID for region-b' 错误 当遇到 `Could not write JSON: Invalid ID for region-b` 这样的错误提示时,通常意味着尝试写入的 JSON 数据中存在不符合预期格式或范围的区域标识符 (ID)。为了有效解决问题,可以从以下几个方面着手: #### 验证数据源中的Region-B ID合法性 确保输入文件中的所有 Region-B IDs 符合定义的标准和约束条件。如果这些IDs是从外部获取或是由其他程序生成,则需确认其准确性。 #### 检查并修正配置文件编码问题 有时不正确的字符集可能导致解析失败或其他异常行为。虽然此案例主要涉及的是无效ID而非编码问题,但考虑到提及到了编码转换的需求[^1],建议也验证下相关配置文件是否确实采用UTF-8编码保存,以排除潜在干扰因素。 #### 审核JSON Schema 或者模式定义 对于有严格结构要求的数据交换格式来说,遵循既定的Schema是非常重要的。如果有可用的JSON Schema文档来描述合法的对象模型,请仔细对照检查每一个字段特别是Region-B ID部分的要求,并据此调整待写入的内容。 #### 编程层面处理非法值 在编写负责创建或修改此类记录的应用逻辑时加入必要的校验机制,在提交前先对即将被序列化的对象实例做一次全面审查,拦截任何可能引起冲突的情况。例如可以使用正则表达式匹配期望的形式或者通过查询数据库等方式核实特定范围内唯一性的保持。 ```python import re def validate_region_b_id(region_b_id): pattern = r'^[A-Za-z0-9_-]+$' return bool(re.match(pattern, str(region_b_id))) if __name__ == "__main__": test_ids = ["valid-id", "invalid/id!", 12345] for id_ in test_ids: print(f"Checking '{id_}': {validate_region_b_id(id_)}.") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值