您好,欢迎访问三七文档
当前位置:首页 > 临时分类 > 26深入体验Java Web开发内幕――核心基础3
深入体验JavaWeb开发内幕张孝祥著声明:如果引用或借鉴本书稿中的图例、解说和讲解技巧,请标明出处,以示对我的辛勤劳动的尊重!这些东西虽然谈不上创造发明,但确实也是花费了我很多时间和精力去总结、归纳出来的。如果有人等我总结、消化后再“巧妙借鉴”,精华和核心全部拿走,然后在随便从书上找到别的知识作补充,以示区别的行为将会极大挫伤我的积极性,希望网友们从道义上对这种行为进行谴责!因涉及商业机密和出版合同,本书中的一些最富有技巧的知识和讲解手法没有提供出来,敬请谅解!————张孝祥第7章会话与状态管理7.2.1什么是CookieCookie是一种在客户端保持HTTP状态信息的技术,它好比商场发放的优惠卡。顾客在一个商场购物结账离开时,商场可以决定是否赠送给顾客一张优惠卡,不同顾客的优惠卡上记载的信息可以不同,例如,记载该顾客累计购物的金额和有效期限。顾客可以决定是否接受这张优惠卡,一旦顾客接受了这张优惠卡,那么他在以后每次光顾该商场时,都将携带这张优惠卡,商场也将根据这张优惠卡上记载的信息进行一些特殊的事务处理,例如,计算折扣率和累加本次购物金额。Cookie是在浏览器访问WEB服务器的某个资源时,由WEB服务器在HTTP响应消息头中附带传送给浏览器的一片数据,WEB服务器传送给各个客户端浏览器的数据是可以各不相同的。浏览器可以决定是否保存这片数据,一旦WEB浏览器保存了这片数据,那么它在以后每次访问该WEB服务器时,都应在HTTP请求头中将这片数据回传给WEB服务器。显然,Cookie最先是由WEB服务器发出的,是否发送Cookie和发送的Cookie的具体内容,完全是由WEB服务器决定的。WEB服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将Cookie信息发送给浏览器,浏览器则通过在HTTP请求消息中增加Cookie请求头字段将Cookie回传给WEB服务器。一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。一个WEB站点可以给一个WEB浏览器发送多个Cookie,这样,在WEB浏览器和WEB服务器之间就可以使用多个Cookie来传递多种信息,例如,用一个Cookie来标识访问者的姓名,用另外一个Cookie来标识该用户登录站点的次数。一个Cookie除了有名称和设置值外,它还可以有一些其他的附加属性,例如,Cookie的有效时间。如果设置了Cookie的有效时间,接受它的浏览器进程将该Cookie保存在计算机硬盘中,只有该Cookie超出有效时间后才被删除,这样的Cookie将被同一台计算机上启动的多个浏览器进程共享。正如一个顾客可以有多家商场提供的优惠卡一样,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。为了防止Cookie塞满客户机的硬盘,浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。如果没有设置Cookie的有效时间,接受它的浏览器进程只将该Cookie保存在自己的内存空间中,在该浏览器进程关闭时,它里面保存的所有Cookie也将随之消失。Cookie在浏览器与WEB服务器之间传送的过程如图7.1所示。深入体验JavaWeb开发内幕张孝祥著实现了一种在浏览器和服务器之间产生有状态会话的方式,它可以把一个浏览器访问的同一个服务器上的所有程序贯连起来,在这些程序之间传递数据。例如,当用户使用浏览器访问某个网站的登录程序进行登录后,无论这个浏览器再访问该网站的哪个程序,其他程序都能知道访问者的身份信息,这是在WEB站点中非常普遍的一个应用。这种应用通常就是采用Cookie技术来实现的,当WEB服务器程序验证登录请求中的用户名和密码后,产生一个标识该用户身份的标识号,然后在响应消息中将该标识号以Cookie的形式传递给浏览器,浏览器在以后每次访问该WEB服务器时,都自动在请求消息头中将标识号又以Cookie的形式返回给WEB服务器,凭借浏览器返回的标识号,WEB服务器的其他程序就能分辨出当前请求是由哪个用户发出的。但是,有一点要注意,不保存在硬盘中的Cookie信息是否可以被同一台计算机上启动的多个浏览器进程共享,不同的浏览器有不同的处理方式。对于IE浏览器来说,保存在其中一个浏览器进程的内存空间中的Cookie是不能被其他浏览器进程共享的,这就会出现同一台计算机上的每个浏览器进程都会与服务器形成各自独立的会话;而对于MozillaFirefox浏览器来说,所有的进程和标签页都共享cookie信息。另外,在IE浏览器中按Ctrl-N键(或者单击“文件”“新建”“窗口”菜单)打开的窗口或者是用javascript的window.open语句打开的窗口,都会共享原窗口的Cookie信息,因为它们属于同一个浏览器进程内部的多个窗口。7.5.3利用Session实现一次性验证码一些人为了窃取他人在某个网站上的帐号,通常采用的办法就是在网站登录页面中不断尝试各种密码进行登录,如果纯粹采用手工方式,由于劳动强度和效率的问题,他们最终都会由于收获渺茫而放弃。但是,如果这些人借用自动化的密码猜测工具来无限制地尝试各种深入体验JavaWeb开发内幕张孝祥著密码,他们成功窃取别人密码的可能性就非常大了。一次性验证码的主要目的就是为了限制人们利用工具软件来暴力猜测密码,其原理和编程实现与7.5.3节的利用Session防止表单重复提交的例子程序基本一样,只是将表单标识号变成了验证码的形式,并且要求用户将提示的验证码手工填写进一个表单字段中,而不是通过表单的隐藏字段自动回传给服务器。为了不给正常用户添加太多的输入麻烦,验证码不能太长,通常为4个随机的字符。为了增加其他工具程序自动识别出验证码的难度,识别码通常以图片的形式展示给用户,并在图片中随机产生一些杂乱的干扰点,如图7.25所示。图7.25服务器程序接收到表单数据后,首先判断用户是否填写了正确的验证码,只有该验证码与服务器端保存的验证码匹配时,服务器程序才开始正常的表单处理流程。验证码使用一次即失效,用户只能重新向服务器发出访问表单填写页面的请求来获得新的验证码,并填写新的验证码后才能再次提交有效的表单请求,这样将大大增加了用户重复操作的难度。密码猜测工具要逐一尝试每个密码的前题条件是先输入正确的验证码,而验证码是一次性有效的,这样基本上就阻断了密码猜测工具的自动地处理过程。下面编写一个利用Session实现一次性验证码的例子程序,整个程序包含三个组件:check_code.html、CheckCodeServlet.java和LogonFormServlet.java。check_code.html是引用验证码图片的FORM表单页面,CheckCodeServlet.java是用于产生带有随机验证码图片的Servlet程序,LogonFormServlet.java则是负责处理FORM表单请求的Servlet程序。动手体验:利用Session实现一次性验证码(1)按上面描述的功能编写如例程7-11、例程7-12和例程7-13所示的程序。例程7-11check_code.htmlh3带有验证码的登录页面/h3formaction=servlet/LogonFormServletmethod=post用户名:inputtype=textname=namebr密码:inputtype=passwordname=passbr验证码:inputtype=textname=check_code深入体验JavaWeb开发内幕张孝祥著=servlet/CheckCodeServletbrinputtype=submitvalue=登录/form例程7-12CheckCodeServlet.javaimportjava.io.*;importjavax.servlet.*;importjavax.servlet.http.*;importjava.awt.*;importjava.awt.image.*;importjavax.imageio.ImageIO;publicclassCheckCodeServletextendsHttpServlet{privatestaticintWIDTH=60;privatestaticintHEIGHT=20;publicvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)throwsServletException,IOException{HttpSessionsession=request.getSession();response.setContentType(image/jpeg);ServletOutputStreamsos=response.getOutputStream();//设置浏览器不要缓存此图片response.setHeader(Pragma,No-cache);response.setHeader(Cache-Control,no-cache);response.setDateHeader(Expires,0);//创建内存图象并获得其图形上下文BufferedImageimage=newBufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);Graphicsg=image.getGraphics();//产生随机的认证码char[]rands=generateCheckCode();//产生图像drawBackground(g);drawRands(g,rands);//结束图像的绘制过程,完成图像g.dispose();深入体验JavaWeb开发内幕张孝祥著将图像输出到客户端ByteArrayOutputStreambos=newByteArrayOutputStream();ImageIO.write(image,JPEG,bos);byte[]buf=bos.toByteArray();response.setContentLength(buf.length);//下面的语句也可写成:bos.writeTo(sos);sos.write(buf);bos.close();sos.close();//将当前验证码存入到Session中session.setAttribute(check_code,newString(rands));//直接使用下面的代码将有问题,Session对象必须在提交响应前获得//request.getSession().setAttribute(check_code,newString(rands));}privatechar[]generateCheckCode(){//定义验证码的字符表Stringchars=0123456789abcdefghijklmnopqrstuvwxyz;char[]rands=newchar[4];for(inti=0;i4;i++){intrand=(int)(Math.random()*36);rands[i]=chars.charAt(rand);}returnrands;}privatevoiddrawRands(Graphicsg,char[]rands){g.setColor(Color.BLACK);g.setFont(newFont(null,Font.ITALIC|Font.BOLD,18));//在不同的高度上输出验证码的每个字符g.drawString(+rands[0],1,1
本文标题:26深入体验Java Web开发内幕――核心基础3
链接地址:https://www.777doc.com/doc-5516032 .html