基于C#和JavaScript的网页验证码优化实现方式(不用Session和Cookie)
来源:互联网 发布:淘宝新手卖家活动 编辑:程序博客网 时间:2024/05/22 01:42
在使用常规方式解决验证码的问题时,通常会遇到这样的问题:Session对于服务器资源耗费很严重,而且当多个客户端同时使用Session时,它的值不能与每个客户端同步,这就导致了将有客户端无故产生“验证码错误”的问题。而Cookie的限制性和局限性也不言而喻,有的用户甚至根本不支持。
经过反复考究和试验,遂产生了优化验证码实现方式的想法。我决定使用少量的JavaScript,C#服务端产生验证码并进行验证,并依赖简单的数据库功能。
基本过程是这样:
1.网页加载时或刷新验证码时,JavaScript产生一个新的验证ID,这个ID须尽可能保持唯一,它是我们验证答案时与客户端对应的依据,也就是说,只有客户端将ID和答案同时提交上来,我们才能在答案库中检索到这个用户当前网页的验证数据。需要注意的是,这个ID在同一用户的各个网页之间也是不同的,这就可以实现多网页同时验证而不会导致冲突。
2.产生新的ID后,JavaScript将这个ID记录在验证表单的一个隐藏的Input控件中,籍以与答案同时提交。然后以这个ID作为参数,刷新验证码图片。(生成新的图片资源链接,比如:"/Verify.aspx?ID=" + ID)。
3.服务端的Verify.aspx是验证码图片的生成器,它随机生成一个新的答案,并根据客户端提交的ID在数据库中增加一个记录,这个记录包含 ①验证ID ②产生验证的时间 ③验证答案,然后以新答案产生一张图片回应给客户端(数据流)。这个第3步是关键所在。
4.客户端网页提交后,服务端根据ID在数据库中查询相应的记录,并检查客户端提交的答案和数据库中的答案是否相符,这是完成验证的最后阶段。为了防止客户端恶意截取ID反复验证,我们在这里要检查验证的时间是否超过我们规定的限制,比如10分钟。
5.为了避免数据库资源开销,我们还需要在服务器上定时清理已经超时作废的验证记录。
需要注意的是,JavaScript产生的ID在验证过程中会有两次提交,第一次是在生成验证码图片时,Verify.aspx接收到这个ID生成答案,并在数据库中记录,然后产生图片;第二次是提交验证的时候,服务器根据这个ID查询答案是否正确。两次缺一不可。用户看到的验证码图片其实是一个微型页面,它同时负责记录数据和生成图片的工作,用户界面得到的只是后者,这两个工作在它的src属性改变时会自动执行。
这种实现方式的好处是非常显著的,经测试,多客户端和同一客户端的多网页之间,可以随意同步进行验证而互不冲突,这弥补了Session值唯一性的缺陷,也大大降低了服务器开销。
JavaScript需要依赖jquery的一小部分功能,现贴上代码
<script type="text/javascript">$(document).ready(function () { RefreshVerifyImage();});function RefreshVerifyImage() { var ID = ""; for (var i = 0; i < 9; i++) { ID = ID + Math.floor(Math.random() * 9); } var IDBox = document.getElementById("VerifyID"); IDBox.value = ID; var CodeImage = document.getElementById("getcode"); CodeImage.src = "/Verify.aspx?VerifyID=" + ID;}</script>
这部分JavaScript会在网页加载完毕时自动执行,也会在用户点击“换一张”链接时被动执行,但需要加载jquery。图片控件的src属性在改变时会自动刷新,这会使服务器上的Verify.aspx记录验证ID,并产生答案和图片,将图片回应给用户。
包含验证码的网页部分代码:
<form action="/Login" id="loginform" method="post"> <label style="display: none;font-size:12px;margin-top:8px;">验证码</label> <input id="txtCaptcha" name="txtCaptcha" maxlength="4" size="10" type="text" value="" /> <img ID="getcode" src="/" /> <A href="javascript:RefreshVerifyImage()"> <span class="v_middle" style="padding-left: 15px;">换一张</span> </A> <input id="VerifyID" maxlength="9" name="VerifyID" type="text" value="" style="position:absolute;visibility:hidden;"/></form>
其中的图片控件getcode就是产生验证码并记录的微型网页,它的src属性在开始时是空的,由JavaScript产生新的ID后进行刷新,而“换一张”链接的点击也会导致它刷新。刷新是通过RefreshVerifyImage函数实现的。
C#中的验证实现类:(直接粘贴的,格式有点变形,请谅解)
public class Verify{public const int EffectiveSeconds = 35; //验证数据的有效时间(秒),避免重复提交验证public const int RecordSaveMinutes = 10; //验证数据在数据库中的保存时间,用于定时清理public const int Length_Answer = 4; //规定验证答案的长度/// <summary>/// 按照指定ID创建一个新的验证码,返回答案/// </summary>/// <param name="ID">验证ID</param>/// <returns></returns>public static string Create(string ID){string Answer = ""; Random rnd; int number1, number2;SqlCommand cmd; SqlDataReader dr; string sql;sql = "SELECT * FROM [Verify] WHERE [ID]='" + ID + "'";using (cmd = new SqlCommand(sql, Conn)){using (dr = cmd.ExecuteReader()){if (dr.Read()) { Answer = dr["Answer"].ToString(); }}}if (string.IsNullOrEmpty(Answer)){rnd = new Random();for (int i = 0; i < Length_Answer; i++){number1 = rnd.Next(0, 9);if (number1 < 5){number2 = rnd.Next(0, 9);Answer += number2;}else{number2 = rnd.Next(97, 122);Answer += ((char)number2).ToString();}}rnd = null;try{sql = "INSERT [Verify]([ID],[Time],[Answer]) VALUES(" + "'" + ID + "'," + "'" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "'," + "'" + Answer + "'" + ")";using (cmd = new SqlCommand(sql, Conn)){cmd.ExecuteNonQuery();}}catch { }}return Answer;}/// <summary>/// 根据验证ID获取图片答案/// </summary>/// <param name="ID">验证ID</param>/// <param name="CheckTime">是否验证超时</param>/// <returns></returns>public static string GetAnswer(string ID, bool CheckTime){string result = "";string sql = "SELECT * FROM [Verify] WHERE [ID]='" + ID + "'";using (SqlCommand cmd = new SqlCommand(sql, Conn)){using (SqlDataReader dr = cmd.ExecuteReader()){if (dr.Read()){DateTime Time = (DateTime)dr["Time"];if (CheckTime){if ((DateTime.Now - Time).TotalSeconds > EffectiveSeconds)throw new Exception("验证请求已超时,请重新提交");}result = dr["Answer"].ToString();}else{throw new Exception("无效的验证请求数据");}}}return result;}/// <summary>/// 清理已经超期无用的验证记录/// </summary>public static void ClearWasteRecords(){try{DateTime EarliestTime = DateTime.Now.AddMinutes(-RecordSaveMinutes);string sql = "DELETE FROM [Verify] WHERE [Time]<'" + EarliestTime.ToString("yyyy-MM-dd HH:mm:ss") + "'";using (SqlCommand cmd = new SqlCommand(sql, Conn)){cmd.ExecuteNonQuery();}}catch { }}}
检查验证码的服务端C#代码:
string VerifyAnswer = Verify.GetAnswer(Request["VerifyID"].ToString(), CheckTime: true);if (string.IsNullOrEmpty(Code) || Code.ToLower().Trim() != VerifyAnswer.ToLower().Trim()) throw new Exception("验证码不正确,请重新输入!");Comlife.Verify.ClearWasteRecords();
数据库表的结构:
ID varchar(9) 验证码序列号
Time datetime 创建时间
Answer varchar(4) 验证码答案
Verify.aspx绘制验证码图片的过程因为太过冗繁,不便在此贴出,如有需要可向我单独索取。
到此全部结束,如果有不明白或测试出现错误,请联系我
QQ:24579039
一点拙见,还请各位高手不要嗤之以鼻以致谩骂,如果有更好的想法也欢迎交流。
- 基于C#和JavaScript的网页验证码优化实现方式(不用Session和Cookie)
- 基于Cookie和session,实现单点登录
- 基于Cookie的Session和禁用Cookie的Session
- 【javascript】cookie和session
- 验证码以及Cookie和Session机制
- 谈谈分布式Session的几种实现方式,Session和Cookie的区别和联系以及Session的实现原理
- 谈谈分布式Session的几种实现方式,Session和Cookie的区别和联系以及Session的实现原理
- cookie session 和登录验证
- session和cookie的使用方法、区别,和分别实现验证登录状态
- 不用session的验证码
- java购物车的实现 基于Session和Cookie的购物车
- 动态网页技术PHP关于cookie和session的分析
- 网页Cookie和Session的初步认识(Java)
- 权限控制和session验证的实现
- C#下的WebClient保存session和cookie的方法
- C#下的WebClient保存session和cookie的方法
- javaweb之Session实现简单的购物(URL重写。Cookie重写指定有效日期)和简单的验证结论
- cookie和session的区别
- redisco,django中的Model共存
- dyld:Expected in: /System/Library/Frameworks/CFNetwork.framework/CFNetwork
- MFC使用HttpGet和HttpPost方法与服务器通信
- 《近匠》爱拍SDK:手游录像分享 爱拍才会赢
- TextView乱换行问题
- 基于C#和JavaScript的网页验证码优化实现方式(不用Session和Cookie)
- thymeleaf api
- Java核心技术卷I:基础知识(原书第8版):13.3 集合框架
- 使用VS2008编译qt源码时提示错误
- 昆仑叶哲华:创业公司应该掌握的6个公关技巧
- 便笺的位置 截图工具的位置
- 微软Visual Studio 2013 With Update3简体中文旗舰版下载(集成UPDATE3,直接安装即可)
- 我对Java内存的认识
- html5---图片上传预览