JCaptcha做验证码遇到的问题引出的思考
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做验证码遇到的问题引出的思考的更多相关文章
- ubuntu 安装(install) pwntcha[一个做"验证码识别"的开源程序]
一.安装 1. sudo apt-get install libsdl1.2-dev libsdl1.2debian sudo apt-get install libsdl1.2-dev(比较大,10 ...
- WPF做验证码,小部分修改原作者内容
原文地址:http://www.cnblogs.com/tianguook/p/4142346.html 首先感谢aparche大牛的帖子,因为过两天可能要做个登录的页面,因此,需要用到验证码,从而看 ...
- 四、自动化平台搭建-Django-如何做验证码
前提:安装包 pip install pillow==3.4.1 1.打开booktest/views.py,创建视图verify_code. from PIL import Image, Ima ...
- 使用Axure做验证码之校验验证码(二)
本次作业,输入验证码,并校验验证码是否正确.上篇文章,介绍了如何获取验证码,本次作业在上次作业的基础上,做进一步的深究. 1.在上次作业中,增加新的元件: 文本框,命名:输入验证码: 增加热区,命名为 ...
- jcaptcha配置验证码
准备开始 首先导入jar包:jcaptcha-my-1.0 /** * web 常量 * @author lx * */ public abstract class Constants { /** 用 ...
- node做验证码
使用了ccap插件 1.安装: 通用方法:npm install ccap 2. cnst ccap= require('ccap')({ width: 128, height: 40, offset ...
- 使用Tesseract-OCR 做验证码识别浅析
使用工具jTessBoxEditor-0.7(这个是在java平台下开发的,所以 它只支持java平台 ,在使用前应该先配置好java环境) tesseract 程序集(因为该程序集是在.net 2. ...
- Django做验证码登录
验证码 关注公众号"轻松学编程"了解更多. 1.作用 在用户登录,注册以及一些敏感操作的时候,我们为了防止服务器被暴力请求,或爬虫爬取,我们可以使用验证码进行过滤,减轻服务器的压力 ...
- nodejs使用 svg-captcha 做验证码及验证
一.需求 使用 nodejs 做后端开发,需要请求验证码,在 github 上看到了 svg-captcha 这个库,发现他是将 text 转 svg 进行返回的,安全性也有保证,不会被识别成文字. ...
随机推荐
- wcf之OperationContextScope
作用:使用消息头向服务发送额外的信息. 1.客户端代码如下: namespace Client { class Program { static void Main(string[] args) { ...
- php 数组 添加元素、删除元素
拆分数组 PHP数组添加一个元素的方式: push(), arr[], Php代码 $arr = array(); array_push($arr, el1, el2 ... eln); 但其实有一种 ...
- CentOS7.0关于libguestfs的bug
libguestfs,libguestfs-tools是用来在不启动虚拟机的情况下,快速简单访问虚拟机磁盘的工具. 今天在CentOS7.0系统上通过guestmount命令去mount虚拟机磁盘的时 ...
- 五 浅谈CPU 并行编程和 GPU 并行编程的区别
前言 CPU 的并行编程技术,也是高性能计算中的热点,也是今后要努力学习的方向.那么它和 GPU 并行编程有何区别呢? 本文将做出详细的对比,分析各自的特点,为将来深入学习 CPU 并行编程技术打下铺 ...
- C. Polycarpus' Dice
在每个位置讨论一下最大值最小值的取值范围就行 #include<cstdio> #include<iostream> #define maxn 200003 using nam ...
- Matlab 矩阵卷积理解(转载)
转载自:http://blog.csdn.net/andrewseu/article/details/51783181 在图像处理的过程中,经常会看到矩阵卷积的概念,比如说用一个模板去和一张图片进行卷 ...
- jQuery获取页面及个元素高度、宽度【转】
获取浏览器显示区域(可视区域)的高度 : $(window).height(); 获取浏览器显示区域(可视区域)的宽度 : $(window).width(); 获取页面的文档高度 ...
- uva624 CD 01背包+输出最优解
link:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- 越狱Season 1-Episode 6: Riots, Drills and the Devil: Part 1
Season 1, Episode 6: Riots, Drills and the Devil: Part 1 - Diamond: Just a few more rides. 就再多玩几次吧 O ...
- 9款精致HTML5/jQuery日历时钟控件源码下载(源码请见百度云) 链接:http://pan.baidu.com/s/1geIXe75 密码:7m4a
现在的网页应用越来越丰富,我们在网页中填写日期和时间已经再也不用手动输入了,而是使用各种各样的日期时间选择控件,大部分样式华丽的日期选择和日历控件都是基于jQuery和HTML5的,比如今天要分享的这 ...