今天将登录功能彻底完成,加入记住密码自动登录功能,密码在客户端进行第一次加密存储。并修改了一些bug,优化js代码,上一版本太乱了。
需要引入插件jquery.md5.js
可直接在IIS下运行;
用户名:Ethan.zhu
密 码:123456789
完整文件下载:http://files.cnblogs.com/zhuyidong/WebApplication1.zip
首先将按钮单击事件的异步验证提取出来作为一个单独的函数,需要将按钮单击事件里面的变量提取出来定义为全局变量,并且增加一个变量editPass(用来标记是自己输入密码,还是从cookies中读取的密码)
var wrongTypeName, // 用户名的错误类型,可以直接作为错误提示信息数组的下标 wrongTypePwd, // 用户密码的错误类型 wrongNameHtml = new Array( "" , " 请输入用户名 " , " 用户名长度太短 " , " 用户名长度超过12位 " , " 您的用户名或密码错误 " , " 超时,请重新登陆 " ), wrongPwdHtml = new Array( "" , " 请输入密码 " , " 密码长度小于6位 " , "" , " 密码中含有非法字符 " ), editPass = false ;
这里从上一篇的按钮单击事件开始:
1 $( " .btn-submit " ).click( function () { 2 wrongTypeName = 0 ; 3 wrongTypePwd = 0 ; 4 var uname = $( " #uname " ).val(), // 用户名 5 pwd = $( " #passwd " ).val(), // 用户密码 6 plength = pwd.length, 7 nlength = uname.length; // 长度 8 if (nlength == 0 ) 9 wrongTypeName = 1 ; 10 if (nlength > 0 && nlength < 2 ) 11 wrongTypeName = 2 ; 12 if (nlength > 20 ) 13 wrongTypeName = 3 ; 14 if (plength == 0 ) 15 wrongTypePwd = 1 ; // 这里是对用户名和密码长度的一个判断,并获取错误信息数组的下标。 16 else { 17 var patrn = / ^(\w){6,20}$ / ; 18 if (plength < 6 ) 19 wrongTypePwd = 2 ; 20 if (plength > 50 ) 21 wrongTypePwd = 3 ; 22 if (plength > 6 && plength < 20 ) { 23 if ( ! patrn.exec(pwd)) 24 wrongTypePwd = 4 ; // 这里是对用户密码合法性的前端判断,并返回错误数组的下标 25 } 26 } 27 28 inputTip( 0 , wrongNameHtml, wrongTypeName); 29 inputTip( 1 , wrongPwdHtml, wrongTypePwd); 30 31 if (wrongTypePwd == 0 && wrongTypeName == 0 ) { // 在用户输入信息完全合法的情况下,即数组下标全部为0 开始执行ajax验证 32 // alert($.cookie("logout")); 33 if (editPass){ 34 pwd = $.md5(pwd); 35 } 36 $( " #passwd " ).val(pwd); 37 $( " #login-form input " ).attr( ' disabled ' , true ); 38 $( ' .remember ' ).unbind( ' click ' ); 39 // 已经向服务器提交了信息,所以将页面上的所有输入框按钮设置成不可用状态,这样可以有效的避免重复提交 40 var remb = $( ' #remember-long ' ).val(); 41 ajaxCheck(uname, pwd, remb); 42 } 43 });
变化在33行和41行,
33行用来判断密码是用户在程序内部退出到登录页面的时候是自行输入还是从cookies中读取的。防止二次加密造成服务器验证失败。
41行主要是将ajax处理过程提取出来,同时加入了服务器验证成功之后的记住密码和取消记住密码的操作,方便阅读:
var ajaxCheck = function (uname, pwd, remb) { $( " .btn-master " ).addClass( " visibility " ); var $params = " user_name= " + decodeURI(uname) + " &user_pwd= " + decodeURI(pwd) + " &remember= " + decodeURI(remb); $.ajax({ type: ' POST ' , url: ' CheckUserLogin.aspx ' , // async: false, cache: false , dataType: ' json ' data: $params, success: function (data, status) { wrongTypeName = data.wrongTypeName; wrongTypePwd = data.wrongTypePwd; var loginSuccess = data.loginSuccess; // 获取服务器返回的json数据 if (loginSuccess == 0 ) { if ($( ' #remember-long ' ).val() == 1 ) { // 记住密码 $.cookie( ' UserName ' , uname, { expires: 7 , path: ' / ' }); $.cookie( ' Password ' , pwd, { expires: 7 , path: ' / ' }); } else if ($( ' #remember-long ' ).val() == 0 ) { // 取消记住的密码,或者没有记住密码 $.cookie( ' UserName ' , null ,{ expires: 7 , path: ' / ' }); $.cookie( ' Password ' , null ,{ expires: 7 , path: ' / ' }); } location.href = " /Members/Members.html " } else { $( " .btn-master " ).removeClass( " visibility " ); $( " #login-form input " ).attr( ' disabled ' , false ); inputTip( 0 , wrongNameHtml, wrongTypeName); inputTip( 1 , wrongPwdHtml, wrongTypePwd); } }, error: function () { wrongTypeName = 5 ; inputTip( 0 , wrongNameHtml, wrongTypeName); $( " #login-form input " ).attr( ' disabled ' , false ); $( ' .remember ' ).bind( ' click ' , function () { checkClick(); }); $( " .btn-master " ).removeClass( " visibility " ); } }) }
页面初始化的时候要对记住密码这个过程进行处理:
var rememberPassword = function (logout) { // 页面加载完成之后执行自动登录检查 var ckname = $.cookie( ' UserName ' ); var ckpwd = $.cookie( " Password " ); if (ckname != "" && ckpwd != "" && ckname != null && ckpwd != null ) { $( ' #remember-long ' ).val( " 1 " ) $( ' #remember-long ' ).attr( ' checked ' , true ); $( " #uname " ).val(ckname); // 用户名 $( ' .reg-item ' ).addClass( ' focus ' ); if (logout == " safe " ){ $.cookie( " logout " , "" ,{ expires: 1 , path: ' / ' }) } else { $( " #passwd " ).val(ckpwd); // 用户密码 $( " .btn-submit " ).trigger( ' click ' ); // 自动登录 } } else { $( ' #remember-long ' ).val( " 0 " ) $( ' #remember-long ' ).attr( ' checked ' , false ); } } var logout = $.cookie( " logout " );// 判断用户是否是从内部退出还是直接打开//如果是从内部退出,那么就不能再次自动登录进去,除非用户刷新了页面 rememberPassword(logout);
下面是完整的全新的前端脚本:
$( function () { var wrongTypeName, // 用户名的错误类型,可以直接作为错误提示信息数组的下标 wrongTypePwd, // 用户密码的错误类型 wrongNameHtml = new Array( "" , " 请输入用户名 " , " 用户名长度太短 " , " 用户名长度超过12位 " , " 您的用户名或密码错误 " , " 超时,请重新登陆 " ), wrongPwdHtml = new Array( "" , " 请输入密码 " , " 密码长度小于6位 " , "" , " 密码中含有非法字符 " ), editPass = false ; $( ' body ' ).focus(); // 让输入框不再自动获取焦点 $( ' .reg-action .reg-input ' ).each( function () { var items = $( this ).parent( ' .reg-item ' ); if ($( this ).val()) { items.addClass( " focus " ); } $( this ).bind( ' focus blur ' , function (event) { var type = event.type; // 获取事件类型 if ($( this ).attr( " id " ) == " passwd " ){ editPass = true ; } if (type == ' focus ' ) { if (items.hasClass( ' error ' )) { $( this ).val( "" ); items.removeClass( ' error ' ); } items.addClass( ' focus ' ); } else if ( ! $( this ).val()) { items.removeClass( ' focus ' ); } }) }); $( " .btn-submit " ).click( function () { wrongTypeName = 0 ; wrongTypePwd = 0 ; var uname = $( " #uname " ).val(), // 用户名 pwd = $( " #passwd " ).val(), // 用户密码 plength = pwd.length, nlength = uname.length; // 长度 if (nlength == 0 ) wrongTypeName = 1 ; if (nlength > 0 && nlength < 2 ) wrongTypeName = 2 ; if (nlength > 20 ) wrongTypeName = 3 ; if (plength == 0 ) wrongTypePwd = 1 ; // 这里是对用户名和密码长度的一个判断,并获取错误信息数组的下标。 else { var patrn = / ^(\w){6,20}$ / ; if (plength < 6 ) wrongTypePwd = 2 ; if (plength > 50 ) wrongTypePwd = 3 ; if (plength > 6 && plength < 20 ) { if ( ! patrn.exec(pwd)) wrongTypePwd = 4 ; // 这里是对用户密码合法性的前端判断,并返回错误数组的下标 } } inputTip( 0 , wrongNameHtml, wrongTypeName); inputTip( 1 , wrongPwdHtml, wrongTypePwd); if (wrongTypePwd == 0 && wrongTypeName == 0 ) { // 在用户输入信息完全合法的情况下,即数组下标全部为0 开始执行ajax验证 // alert($.cookie("logout")); if (editPass){ pwd = $.md5(pwd); } $( " #passwd " ).val(pwd); $( " #login-form input " ).attr( ' disabled ' , true ); $( ' .remember ' ).unbind( ' click ' ); // 已经向服务器提交了信息,所以将页面上的所有输入框按钮设置成不可用状态,这样可以有效的避免重复提交 var remb = $( ' #remember-long ' ).val(); ajaxCheck(uname, pwd, remb); } }); var inputTip = function (index, tipHtml, tipNum) { $( " .reg-tip " ).eq(index).html(tipHtml[tipNum]); if (tipNum > 0 ) $( " .reg-item " ).eq(index).addClass( " error " ); else $( " .reg-item " ).eq(index).removeClass( " error " ); } // 定义错误提示信息页面显示函数。由于页面只有两个输入框所以我这里直接指定了index,如果页面上有很多,可以使用$(this).index() var ajaxCheck = function (uname, pwd, remb) { $( " .btn-master " ).addClass( " visibility " ); var $params = " user_name= " + decodeURI(uname) + " &user_pwd= " + decodeURI(pwd) + " &remember= " + decodeURI(remb); $.ajax({ type: ' POST ' , url: ' CheckUserLogin.aspx ' , // async: false, cache: false , dataType: ' json ' , data: $params, success: function (data, status) { wrongTypeName = data.wrongTypeName; wrongTypePwd = data.wrongTypePwd; var loginSuccess = data.loginSuccess; // 获取服务器返回的json数据 if (loginSuccess == 0 ) { if ($( ' #remember-long ' ).val() == 1 ) { // 记住密码 $.cookie( ' UserName ' , uname, { expires: 7 , path: ' / ' }); $.cookie( ' Password ' , pwd, { expires: 7 , path: ' / ' }); } else if ($( ' #remember-long ' ).val() == 0 ) { // 取消记住的密码,或者没有记住密码 $.cookie( ' UserName ' , null ,{ expires: 7 , path: ' / ' }); $.cookie( ' Password ' , null ,{ expires: 7 , path: ' / ' }); } location.href = " /Members/Members.html " } else { $( " .btn-master " ).removeClass( " visibility " ); $( " #login-form input " ).attr( ' disabled ' , false ); inputTip( 0 , wrongNameHtml, wrongTypeName); inputTip( 1 , wrongPwdHtml, wrongTypePwd); } }, error: function () { wrongTypeName = 5 ; inputTip( 0 , wrongNameHtml, wrongTypeName); $( " #login-form input " ).attr( ' disabled ' , false ); $( ' .remember ' ).bind( ' click ' , function () { checkClick(); }); $( " .btn-master " ).removeClass( " visibility " ); } }) } var checkClick = function () { if ($( ' #remember-long ' ).attr( ' checked ' )) { $( ' #remember-long ' ).attr( ' checked ' , false ); $( ' #remember-long ' ).val( " 0 " ) } else { $( ' #remember-long ' ).attr( ' checked ' , true ); $( ' #remember-long ' ).val( " 1 " ) } } $( ' .remember ' ).bind( ' click ' , function () { checkClick(); }); $( " #remember-long " ).click( function () { checkClick(); }); // 记住登录的checkbox和label点击的绑定。 if ($.browser.msie && $.browser.version == " 6.0 " ) { // 帮助微软消灭ie6 if ($.cookie( ' masterShow ' ) != " hidden " ) $( ' body ' ).append( ' <div class="master"><p>您的浏览器是<strong>IE6.0</strong>,漏洞较多,用户体验较差,微软官方将要放弃支持,为了自身电脑安全和获取最佳用户体验建议你根据自身需求升级至<a href="http://windows.microsoft.com/zh-CN/internet-explorer/downloads/ie-8" target="_blank" class="red"><strong>IE8.0</strong></a>以上版本或者使用<a href="http://firefox.com.cn/" target="_blank" class="red"><strong>火狐</strong></a>浏览器</p></div><div class="m-close m-close-short">关闭</div><div class="m-close m-close-long">不再显示</div> ' ); $( " .master " ).delay( 1000 ).slideDown( '' , function () { $( " .m-close " ).fadeIn(); }); $( " .m-close-short " ).click( function () { $( " .m-close " ).fadeOut( '' , function () { $( " .master " ).slideUp(); }); }); $( " .m-close-long " ).click( function () { $( " .m-close " ).fadeOut( '' , function () { $( " .master " ).slideUp(); $.cookie( ' masterShow ' , ' hidden ' ); }); }); } var rememberPassword = function (logout) { // 页面加载完成之后执行自动登录检查 var ckname = $.cookie( ' UserName ' ); var ckpwd = $.cookie( " Password " ); if (ckname != "" && ckpwd != "" && ckname != null && ckpwd != null ) { $( ' #remember-long ' ).val( " 1 " ) $( ' #remember-long ' ).attr( ' checked ' , true ); $( " #uname " ).val(ckname); // 用户名 $( ' .reg-item ' ).addClass( ' focus ' ); if (logout == " safe " ){ $.cookie( " logout " , "" ,{ expires: 1 , path: ' / ' }) } else { $( " #passwd " ).val(ckpwd); // 用户密码 $( " .btn-submit " ).trigger( ' click ' ); // 自动登录 } } else { $( ' #remember-long ' ).val( " 0 " ) $( ' #remember-long ' ).attr( ' checked ' , false ); } } var logout = $.cookie( " logout " ); // 判断用户是否是从内部退出 rememberPassword(logout); $(document).bind( ' keydown ' , ' return ' , function () { $( " .btn-submit " ).trigger( ' click ' ); }); })
关于页面中涉及的后台程序,我用了页面级别的aspx,当然你也可以使用ashx来处理。这个后台处理负责验证密码是否正确并在用户正确登录的情况下设置session值,如果需要演示,可以在后台定义常量来做验证判断:
Hashtable ht = new Hashtable(); string uname = Request.Params[ " user_name " ]; string pwd = Request.Params[ " user_pwd " ]; int wrongTypeName = 0 ; int wrongTypePwd = 0 ; uname = PageValidate.InputText(uname, 30 ); if (Validator.StrIsNullOrEmpty(uname)) { wrongTypeName = 1 ; } if (Validator.StrIsNullOrEmpty(pwd)) { wrongTypePwd = 1 ; } if ( ! string .IsNullOrEmpty(uname) && ! string .IsNullOrEmpty(pwd)) { // 以下使用常量来做演示: string userName = " ethan.zhu " ; string password = "" ; // 需要MD5加密之后的字符串 if (uname == userName && password == pwd ) ht.Add( " loginSuccess " , 0 ); else wrongTypeName = 4 ; // 返回用户名或密码错误 if (wrongTypeName > 0 || wrongTypePwd > 0 ) { ht.Add( " wrongTypeName " , wrongTypeName); ht.Add( " wrongTypePwd " , wrongTypePwd); } Response.Write(CreateJsonParams(ht)); } Response.End(); }
将Hashtable转换成json:
public static string CreateJsonParams(Hashtable items) { string returnStr = "" ; foreach (DictionaryEntry item in items) { returnStr += " \" " + item.Key.ToString() + " \":\" " + item.Value.ToString() + " \", " ; } return " { " + returnStr.Substring( 0 , returnStr.Length - 1 ) + " } " ; }