验证码实现的详细以及前端验证的难点解析

2012/6/19   星期二  天气阴

实现验证码这个功能是前不久的事情了,主要是给玛丽英语网站界面的报名页面做的。由于网站一开始没有验证功能,导致受到了一些非法攻击,数据库出现了许多垃圾数据和非法数据。鉴于此,在后期维护的时候让我在里面添加一个验证功能。

说起来验证码的实现倒不是难点,网上搜一下验证码,你可以就到得到很多的源码,那么我写这片文章的目的也不是专门为了说明如何实现这个验证码,而是在实现的过程遇到的一些问题,尤其是对于sessionjavaScript的深入理解做一些记录和探究。

首先,我从网上下载了一份最常见的验证码实现模板,有三个JSP组成,一张是显示页面,一张是验证码的生成页面,一张是用来伪装成后台的验证界面。原理很简单,我们得到验证码的随机数,和页面上输入的数字比较,来判断是否验证通过。验证码的随机数通常保存在session里面,session的机制会在后面详细描述。

image.jsp页面生成验证码的图片,应用了一些画图类和输入输出流,可以把image.jsp理解成为image.jpeg,每次刷新或者重新载入就会产生一个新的随机验证码。一般来说,简单基础的验证码都是四位数字,在安全性要求一般的网站应用绝对足够。在生成的时候把int类型的数字直接画出来,这样在破解的时候就需要用到图像处理技术,使得验证码具有好的安全性,如果只是数字,会很容易识别。我们会在图像中加入一些增大图像识别的乱码或者线条。

在生成图像的时候,其实把随机数保存在session里面。session.setArribute("rand",rand);这样我们可以在任何地方获取到这个session。然后我们再获取到前端输入的数据,与保存在session里面的数据进行比较,进而验证。说起来很简单,而且本来也确实应该很简单。如果在是在项目初就设计编写了验证码,我相信会非常简单。而现在我是在一个完整的项目上添加一个验证码,按照我的设想,难度也应该不会很大,但是现实是这样的:原先作者为了进行url保护,对所有的url进行了重写,(使用urlrewrite技术)意思就是我无法直接访问在根目录下的JSP,这样我的页面显示首先就存在了问题,image.jsp是直接嵌入式的,也就是当作jpeg的图片资源来使用,那么我现在无法直接访问,也就无法载入image.jsp。同样我的验证也无法在另一张JSP验证,因为一旦提交,就直接发送到后端数据了,本着尽量减少源码修改的原则,我一直想让它在前端验证,前端显示验证结果,于是才有了以下内容的探讨和思考。

我首先解决了Image.jsp的载入问题,也就是我现在能显示验证码,并且在session里面也有值了,我只需要获得前端输入的数据就可以验证了。我查了一下,在JSP页面获取文本框数据可以用JS代码来操作,具体代码如下:

<script>

function validateCode() {

// 获取Id为“yanzhengma”的对象的value值

var codeValue = document.getElementById("yanzhengma").value;

alert("rand:"+rand);

}

</script>

实现证明,是可以这样获取到节点数据的。只需要给Input节点加ID

那么,是不是我在这个JSP代码里面获取session里面的值就可以进行验证了呢?

这是我原先的设想:

<script>

function validateCode() {

// 获取Id为“yanzhengma”的对象的value值

var codeValue = document.getElementById("yanzhengma").value;

var rand="<%=request.getSession().getAttribute("rand")%>";

alert("rand:"+rand);

if (codeValue == rand) {

alert("验证通过");

else {

alert("请正确输入验证码!");

}

}

</script>

    首先说明一点,JS是无法直接获取session的,为什么?因为JS是运行在本地浏览器的,为session保存在服务器端,如果不发送Ajax请求,是无法获取到session里面的值呢,但是以上方法为什么可行呢,是因为通过了一步转换,用java语句来获得session值,再赋值给JS代码里的rand

    但是事实证明,理想是美好的,现实是残酷的,这也是不行的。

为什么?我尝试很久,如果直接在image.jsp页面里面,system.out打印session里面的值,是正常的,说明session没有问题,然后再看alert的值,总是乱七八糟,和session的值不一样。这困扰了我很久。

后来我又尝试了一种新的思路,把session的值放在隐藏域里面,相当于一个默认的节点带了session值,然后在JS代码里面获取隐藏域里面的值,这样就可以进行前端判断了。这个也是不错的想法,于是我信心满满地做了,但是结果还是获得的值与原先的不匹配,通过多次实验我发现,刷新后第一次获取session的值alert出来为null,下次alert出来的session值总是为前一次显示的验证码。这样的结果看起来就已经有点眉目了。

然后我度娘了一下session以及JS。前面我们提到session保存在服务器端,从java内存的角度分析,它应该是保存在服务器内存中的常量池中,我们可以用java语句或者Ajax请求获取,但是无法用JS代码直接获取。然后我才会想到用其他折中的方法来变相在JS获取session值。但是这涉及到JSJava的执行顺序问题。JS是客户端的,可以直接执行,而Java需要编译,在可能就是某种程度上导致先运行JS的原因了。而且如果这样理解,前面的矛盾也都可以解释了。为什么第一次运行的时候alert的值是null,因为先运行JS,而此时它还没获取到session的值,然后才运行Java代码,这时候显示验证码,并且在session中保存了这样一个值。然后下次运行的时候又是先执行JS代码,所以这时会显示上一次的验证码结果,而我们看到的是这次执行Java代码得到的值。

总的来说,理解透这个问题,就可以明白,要想在同一个界面做到前端验证,除了发送Ajax请求,没什么其他办法了,而发送到另一张JSP页面其实也是相当于后台验证的一种。后来我还是采用了后台验证,因为后台验证就不存在这些问题了。

在解决这个验证码问题的同时我也进一步加深对了对sessionJS的理解,虽然从实现上来说,我一开始就可以用后台验证,而且很快就可以实现,但是我相信这样的探索对我的开发还是有帮助的。

下面附上验证码源代码一份:

http://wenku.baidu.com/view/4097492fe2bd960590c67778.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值