JCaptcha用来做用户登录时期的验证码的,但是今天将开放的应用系统部署到生产环境的时候,遇到了问题,总是提示验证码不对。后台报出来下面的错误:

  com.octo.captcha.service.CaptchaServiceException: Invalid ID, could not validate unexisting or already validated captcha
at com.octo.captcha.service.AbstractCaptchaService.validateResponseForID(AbstractCaptchaService.java:)
at com.octo.captcha.service.AbstractManageableCaptchaService.validateResponseForID(AbstractManageableCaptchaService.java:)
at com.tk.cms.core.shiro.JCaptcha.validateResponse(JCaptcha.java:)
at com.tk.cms.core.shiro.JCaptchaValidateFilter.isAccessAllowed(JCaptchaValidateFilter.java:)
at org.apache.shiro.web.filter.AccessControlFilter.onPreHandle(AccessControlFilter.java:)
at org.apache.shiro.web.filter.PathMatchingFilter.isFilterChainContinued(PathMatchingFilter.java:)
at org.apache.shiro.web.filter.PathMatchingFilter.preHandle(PathMatchingFilter.java:)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:)
at org.apache.shiro.web.servlet.AbstractShiroFilter$.call(AbstractShiroFilter.java:)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:)
at java.lang.Thread.run(Thread.java:)

网上也有很多种方案,其中就说到过,如下代码处有问题(红色部分代码执行的不是时候):

     /**
* Method to validate a response to the challenge corresponding to the given ticket and remove the coresponding
* captcha from the store.
*
* @param ID the ticket provided by the buildCaptchaAndGetID method
* @return true if the response is correct, false otherwise.
* @throws CaptchaServiceException if the ticket is invalid
*/
public Boolean validateResponseForID(String ID, Object response)
throws CaptchaServiceException {
if (!store.hasCaptcha(ID)) {
throw new CaptchaServiceException("Invalid ID, could not validate unexisting or already validated captcha");
} else {
Boolean valid = store.getCaptcha(ID).validateResponse(response);
store.removeCaptcha(ID);
return valid;
}
}

其实,我也仔细debug过,这个验证码错误的问题,其实是在store这个FastHashMap中通过sessionId为key去找是否存在这么一个jcaptcha实例,若没有就报exception了,最后就是验证码错误。 其实,这不是我应用中的问题。

针对这个问题,我一开始,怀疑是自己的代码写的出了问题,总在分析代码的流程,但是疑点是,我直接访问tomcat所在的机器,没有出现验证码的错误。但是一旦上到nginx的负载均衡环境,就遇到这个问题。想想,为何session不对???看看应用中的日志,sessionID和浏览器中cookie中的sessionId,总是不一样。。。这个就是问题的表象,根源在什么地方呢???

后来仔细看了看我们服务器的nginx的反向代理配置,发现upstream部分,没有配置负载均衡的策略,什么都没有配置呀。。。。我倒,什么都没有指定,那就是default的roundrobin啊,轮询啊。。。。我的神,这一个应用服务会有多少次http请求到达后端啊,每次轮询,那session对于后端的服务来说,岂不是没有地方hold了。。。不行。这个就是问题的根源。。。

我们的session没有专门的共享方案,所以,为了改动最小化,最好不改代码的情况下,我选择将upstream部分添加ip_hash策略,这样子能保证同一个IP请求的所有http都锁定在后端的一个服务上,这样子就不存在session丢失的问题了。

  upstream cms {
server 10.130.14.51:;
server 10.130.14.53:;
ip_hash;
}

加上了上面的红色部分,问题解决!

思考:

1. 负载均衡环境下,session的管理是个问题,忽视这个问题,会造成登录都不可能完成。 遇到登录或者类似我这里验证码总是不对的情况,可以想想,是不是session的管理不到位!

2. 常见的session管理,比较靠谱的可控的方式有类似我这里的方案,基于ip_hash的策略,还有,就是专门的开发接口来管理session,不用tomcat容器的那一套。比如将session放在mysql里面,或者redis等中间件里面。

JCaptcha做验证码遇到的问题引出的思考的更多相关文章

  1. ubuntu 安装(install) pwntcha[一个做"验证码识别"的开源程序]

    一.安装 1. sudo apt-get install libsdl1.2-dev libsdl1.2debian sudo apt-get install libsdl1.2-dev(比较大,10 ...

  2. WPF做验证码,小部分修改原作者内容

    原文地址:http://www.cnblogs.com/tianguook/p/4142346.html 首先感谢aparche大牛的帖子,因为过两天可能要做个登录的页面,因此,需要用到验证码,从而看 ...

  3. 四、自动化平台搭建-Django-如何做验证码

    前提:安装包   pip install pillow==3.4.1 1.打开booktest/views.py,创建视图verify_code. from PIL import Image, Ima ...

  4. 使用Axure做验证码之校验验证码(二)

    本次作业,输入验证码,并校验验证码是否正确.上篇文章,介绍了如何获取验证码,本次作业在上次作业的基础上,做进一步的深究. 1.在上次作业中,增加新的元件: 文本框,命名:输入验证码: 增加热区,命名为 ...

  5. jcaptcha配置验证码

    准备开始 首先导入jar包:jcaptcha-my-1.0 /** * web 常量 * @author lx * */ public abstract class Constants { /** 用 ...

  6. node做验证码

    使用了ccap插件 1.安装: 通用方法:npm install ccap 2. cnst ccap= require('ccap')({ width: 128, height: 40, offset ...

  7. 使用Tesseract-OCR 做验证码识别浅析

    使用工具jTessBoxEditor-0.7(这个是在java平台下开发的,所以 它只支持java平台 ,在使用前应该先配置好java环境) tesseract 程序集(因为该程序集是在.net 2. ...

  8. Django做验证码登录

    验证码 关注公众号"轻松学编程"了解更多. 1.作用 在用户登录,注册以及一些敏感操作的时候,我们为了防止服务器被暴力请求,或爬虫爬取,我们可以使用验证码进行过滤,减轻服务器的压力 ...

  9. nodejs使用 svg-captcha 做验证码及验证

    一.需求 使用 nodejs 做后端开发,需要请求验证码,在 github 上看到了 svg-captcha 这个库,发现他是将 text 转 svg 进行返回的,安全性也有保证,不会被识别成文字. ...

随机推荐

  1. PHP 转换snmp的时间格式

    function convert_snmp_timeticks($timeticks) { if(!is_numeric($timeticks)) { return FALSE; } //如果是字符串 ...

  2. 创建交互式shell脚本对话框

    当你在终端环境下安装新的软件时,你可以经常看到信息对话框弹出,需要你的输入,比如:RHEL/CentOS自带的setup,对话框的类型有密码箱.检查表.菜单等等.他们可以引导你以一种直观的方式输入必要 ...

  3. Git常用命令总结(超实用)

    导读 Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目.一般来说,日常使用Git只要记住下图6个命令,就可以了.但是熟练使用,恐怕要记住60-100个命令. 下面是我整 ...

  4. Java BTrace实战(1)--BTrace的入门和使用

    前言: 对线上的java服务, 往往采用日志进行问题处理和分析. 倘若日志缺乏相关的信息时, 那又该如何处理? 远程调试会影响服务的正常工作, 修改代码重新部署的方案其实时性和灵活性难以保证(线上服务 ...

  5. JavaScript 编写多线程代码引用Concurrent.Thread.js(转)

    这是一个很简单的功能实现: <script type="text/javascript" src="Concurrent.Thread.js">&l ...

  6. 在JSP页面下使用AJAX实现用户名存在的检测

    <script type="text/javascript">     function init(){         document.getElementById ...

  7. 配置DNS

    1.将DNS解析服务器添加到:/etc/resolv.conf 2.打开DNS相关配置:sed -i 's/^hosts:[ \t]*files[ \t]*$/& dns/' /etc/nss ...

  8. ARM1138@库函数速查

    1. GPIO库函数 可实现的功能: 获得/设置指定管脚的方向(输入.输出)和模式(硬件控制) 获取/设置指定管脚的配置(驱动强度2/4/8/8_SCmA.管脚模式:推挽(弱上拉/弱下拉)/开漏(弱上 ...

  9. apply通过实例理解

    测试->运行环境chrom console >var aaa = {a:1,b:2,c:function(){console.log(this.a)}} 运行结果:undefined &g ...

  10. 自然语言处理3.3——使用Unicode进行文字处理

    全世界有多种语言,经常需要应用程序处理不同的语言和字符集.下面将介绍如何利用Unicode处理使用非ASCII字符集文字. 1.什么是Unicode Unicode支持一百万种以上的字符,每一个字符分 ...