在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
任务需求:做一个登录,拥有自动记住账号和密码的功能,要保证安全性,ajax,无刷新,良好的用户体验.(母板页) 这是前台页面,要求实现用户登录 首先我们分析, 用户需求: 1. 登录以后,登录框隐藏,并且欢迎登录的框显示,并且,左上角登录的按钮消失,安全退出显示. 2. 如果选择记住帐号和密码,下次登录直接登录,并且保证安全性. 实现过程: 首先,登录的时候发出ajax请求,用户验证登录,登录以后,保存当前用户名和密码到cookies中,注意,密码要用md5加密,md5是根据用户的机器配置生成的,并且返回登录状态和用户名的json数据 第二次登录的时候,检测用户状态,如果用户cookies保存的用户名和密码,根据用户名读取用户密码,并进行md5加密,检验两次密码是否相同,如果相同就返回json数据,登录状态true和用户名,如果cookies中只有用户名,那么返回登录状态为false和用户名 前台主要代码: 复制代码 代码如下: <%@ Master Language="C#" AutoEventWireup="true" CodeFile="Left_Top_Dwon.master.cs" Inherits="Left_Top_Dwon" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> <link href="css/top_foot.css" rel="stylesheet" type="text/css" /> <link href="css/style.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src='<%=ResolveUrl("js/main_nav.js")%>'></script> <script type="text/javascript" src='<%=ResolveUrl("js/nav.js") %>'></script> <script src='<%=ResolveUrl("Admin/scripts/jquery-1.7.1.min.js")%> ' type="text/javascript"></script> <script type="text/javascript"> //检测登录状态 function CheckLoginState() { $.ajax({ url:"Member/Data/GetMemberInfo.ashx?method=CheckLoginStatus", type:"post", success:function(data,status){ var jsonInfo= $.parseJSON(data); // alert(data); //同时记住账号和密码 if(jsonInfo.Status&&jsonInfo.UserName!="") { $("#divNotLogin").hide(); $("#divIsLogin").show(); $("#liLogin").hide(); $("#liLogout").show(); $("#lbUserName").text(jsonInfo.UserName); } //如果只记住账号 else if(jsonInfo.Status&&jsonInfo.UserName==""){ $("#divNotLogin").show(); $("#divIsLogin").hide(); $("#liLogin").show(); $("#liLogout").hide(); $("#txtUserName").val(jsonInfo.UserName); } else{ $("#divNotLogin").show(); $("#divIsLogin").hide(); $("#liLogin").show(); $("#liLogout").hide(); } } }); } $(function(){ //第一次登录需要检测是否自动登录 CheckLoginState(); //获取新闻类别 $.ajax({ url:'<%=ResolveUrl("Admin/News/Data/GetNewsInfo.ashx?method=GetNewsTypeForCombox")%>', type:"get", success:function(text){ var JsonData=$.parseJSON(text); $("#m2").empty();//先清空m2子元素的内容 $.each(JsonData,function(key,value){ //注意这里 //这里链接还需要添加具体页面 $("#m2").append('<a href=\"'+'<%=ResolveUrl("News/NewsList.aspx?TypeId=")%>'+value.TypeId+'\">'+value.TypeName+'</a>'); }); } }); //获取工艺知识类别 $.ajax({ url:'<%=ResolveUrl("Admin/Product/Data/GetProductInfo.ashx?method=GetTopCraftTypeInfo")%>', type:"get", success:function(text){ var JsonData=$.parseJSON(text); $("#m1").empty();//先清空m2子元素的内容 $.each(JsonData,function(key,value){ //注意这里 //这里链接还需要添加具体页面 $("#m1").append('<a href=\"'+'<%=ResolveUrl("CraftKnowledge/CraftKnowledgeList.aspx?FId=")%>'+value.FId+'\">'+value.TypeName+'</a>'); }); } }); //登录 $("#aLogin").click(function(){ var Name=$("#txtUserName").val(); var pwd=$("#txtPwd").val(); var cbName=$("#cbUserName").attr("checked"); var cbPwd=$("#cbPwd").attr("checked"); if(Name==""||pwd=="") { alert("用户名或密码不能为空!"); return; } if(cbName=="checked") cbName="1"; else cbName="0"; if(cbPwd=="checked") cbPwd="1"; else cbPwd="0"; var Data={"Name":Name,"Pwd":pwd,"cbName":cbName,"cbPwd":cbPwd } $.ajax({ url:"Member/Data/GetMemberInfo.ashx?method=MemberLogin", type:"post", data:Data, success:function(ReturnData,status){ var jsonInfo= $.parseJSON(ReturnData); if(jsonInfo.Status) { $("#divNotLogin").hide(); $("#divIsLogin").show(); $("#liLogin").hide(); $("#liLogout").show(); $("#lbUserName").text(jsonInfo.UserName); } else{ alert("您输入的帐号或密码错误!也有可能您的帐号未邮箱激活!"); } } }); }); }); </script> <asp:ContentPlaceHolder ID="head" runat="server"> </asp:ContentPlaceHolder> </head> <body> <div class="sheel"> <div class="header"> <div class="top_side"> <ul> <li id="liLogin"><a href="#">登录</a> | </li> <li><a href="#">注册</a> </li> <li>|<a href="#">个人信息</a> </li> <li>|<a href="#">我的收藏夹</a> </li> <li>|<a href="#">我的留言</a> </li> <li>|<a href="#">总站留言</a> </li> <li id="liLogout">|<a id="A2" href='<%=ResolveUrl("Member/Data/GetMemberInfo.ashx?method=MemberLogout")%>'>安全退出</a></li> </ul> </div> <div class="nav"> <ul id="sddm"> <li><a href="#">首 页</a> </li> <li><a href="#">工艺概况</a></li> <li><a href="#" onmouseover="mopen('m1')" onmouseout="mclosetime()">工艺知识</a> <div id="m1" onmouseover="mcancelclosetime()" onmouseout="mclosetime()"> <a href="#">大吴泥塑</a> <a href="#">金漆木雕</a> <a href="#">潮州刺绣</a> <a href="#">潮州陶瓷</a> </div> </li> <li><a href="#">作品展览</a></li> <li><a href="#">非遗作品</a></li> <li><a href="#" onmouseover="mopen('m2')" onmouseout="mclosetime()">新闻中心</a> <div id="m2" onmouseover="mcancelclosetime()" onmouseout="mclosetime()"> <a href="#">大吴泥塑</a> <a href="#">金漆木雕</a> <a href="#">潮州刺绣</a> <a href="#">潮州陶瓷</a> </div> </li> <li><a href="#">大师风采</a></li> <li><a href="#">企业展示</a></li> <li><a href="#">联系我们</a></li> </ul> </div> </div> <div class="content"> <div class="left_side"> <form id="fLogin"> <div class="logo_bottom"> </div> <div class="login"> <h4> 用户登录</h4> <div class="lg_table" id="divNotLogin"> <table class="table1" width="198" cellpadding="0" cellspacing="0" border="0"> <tr> <td width="40" align="right"> 用户名 </td> <td width="108" align="center"> <input type="text" id="txtUserName" name="txtUserName" /> </td> <td width="50" rowspan="2"> <a href="#" id="aLogin"> <img src='<%=ResolveUrl("images/login.png")%>' alt="登录" /></a> </td> </tr> <tr> <td align="right"> 密码 </td> <td align="center"> <input type="password" name="txtPwd" id="txtPwd" /> </td> </tr> </table> <div class="border"> </div> <table class="table2" width="190" cellpadding="0" cellspacing="0" border="0"> <tr> <td width="90"> <a href="#"> <img src='<%=ResolveUrl("images/lg_forget.png")%>' alt="忘记密码" /></a> </td> <td width="100"> <a href="#"> <img src='<%=ResolveUrl("images/zhuce.png")%>' alt="注册" /></a> </td> </tr> <tr> <td> <input type="checkbox" name="cbUserName" id="cbUserName" /><span>记住用户名</span> </td> <td> <input type="checkbox" name="cbPwd" id="cbPwd" /><span>记住密码</span> </td> </tr> </table> </div> <div class="lg_table" id="divIsLogin"> <table id="tbIsLogin" class="table1" width="198" cellpadding="0" cellspacing="0" border="0"> <tr> <td class="style1" style="height: 90px"> <font style="color: Red">欢迎您回来!</font><br /> 尊敬的的<font style="color: Red"><label id="lbUserName"></label></font>用户! </td> </tr> <tr> <td align="center" class="style2"> <a href="###">查看个人信息</a> | <a id="A1" href='<%=ResolveUrl("Member/Data/GetMemberInfo.ashx?method=MemberLogout")%>'>退出</a> </td> </tr> </table> </div> </div> </form> <div class="enter enter1"> <a href="#"> <img src='<%=ResolveUrl("images/master.png")%>' alt="大师入口" title="大师入口" /></a></div> <div class="enter enter2"> <a href="#"> <img src='<%=ResolveUrl("images/company.png")%>' alt="企业入口" title="企业入口" /></a></div> <div class="paihang"> <h3> <p class="hide"> 推荐排行榜</p> <p> <a href="#">更多</a></p> </h3> <ul class="ph_ul" id="ph1"> <li><a href="#" onmouseover="setph(0);" class="ph_hover">大师推荐</a></li> <li><a href="#" onmouseover="setph(1);">工艺品推荐</a></li> <li><a href="#" onmouseover="setph(2);">企业推荐</a></li> </ul> <div class="ph_p" id="ph2"> <ul style="display: block;"> <li class="ph_li1"><a href="#" class="phplihover">周少君</a></li> <li class="ph_li2"><a href="#">周少君</a></li> <li class="ph_li3"><a href="#">周少君</a></li> <li class="ph_li4"><a href="#">周少君</a></li> <li class="ph_li5"><a href="#">周少君</a></li> </ul> <ul> <li class="ph_li1"><a href="#" class="phplihover">大大个</a></li> <li class="ph_li2"><a href="#">大大个</a></li> <li class="ph_li3"><a href="#">大大个</a></li> <li class="ph_li4"><a href="#">大大个</a></li> <li class="ph_li5"><a href="#">大大个</a></li> </ul> <ul> <li class="ph_li1"><a href="#" class="phplihover">小小粒</a></li> <li class="ph_li2"><a href="#">小小粒</a></li> <li class="ph_li3"><a href="#">小小粒</a></li> <li class="ph_li4"><a href="#">小小粒</a></li> <li class="ph_li5"><a href="#">小小粒</a></li> </ul> </div> </div> <div class="question"> <h3> <p class="hide"> 参与调查</p> </h3> <table width="200"> <tr> <td colspan="2"> <b>Q.</b><span>您最喜欢以下哪种工艺品?</span> </td> </tr> <tr> <td> <input type="radio" /><span>泥塑</span> </td> <td> <input type="radio" /><span>木雕</span> </td> </tr> <tr> <td> <input type="radio" /><span>陶瓷</span> </td> <td> <input type="radio" /><span>石雕</span> </td> </tr> <tr> <td> <a href="#"> <img src='<%=ResolveUrl("images/sumbit.gif")%>' alt="提交" /></a> </td> <td> <a href="#"> <img src='<%=ResolveUrl("images/see.gif")%>' alt="查看结果" /></a> </td> </tr> </table> </div> <div class="search"> <div class="search_thing"> <table width="225"> <tr> <td height="25"> <select name="select" class="select"> <option>木雕</option> <option>泥塑</option> <option>陶瓷</option> </select> </td> <td height="25"> <input type="text" value="" /> </td> </tr> <tr> <td colspan="2"> <a href="#"> <img src='<%=ResolveUrl("images/search.png")%>' alt="搜索" /></a> </td> </tr> <tr> <td colspan="2" class="high_search"> <a href="search.html">前往高级搜索>></a> </td> </tr> </table> </div> </div> </div> <div class="right_side"> <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server"> </asp:ContentPlaceHolder> </div> <div class="footer"> <div class="s_nav"> <ul> <li><a href="#">在线留言</a>|</li> <li><a href="#">联系我们</a>|</li> <li><a href="#">关于我们</a>|</li> <li><a href="#">企业信息</a>|</li> <li><a href="#">招商合作</a></li> </ul> </div> <div class="foot"> <p> <span>广东省潮州</span> <span>2011 © All RIGHTS RESERVED. [版权所有] 学生创新活动中心</span> </p> <p> <span>制作与维护:计算机工程研发实验室</span><span>联系QQ群:73983871</span></p> </div> </div> </div> </div> </body> </html> 接下来,后台相应请求: 复制代码 代码如下: <%@ WebHandler Language="C#" Class="GetMemberInfo" %> using System; using System.Web; using Common; using czcraft.Model; using czcraft.BLL; using System.Web.SessionState; public class GetMemberInfo : IHttpHandler, IRequiresSessionState { // //记录日志 private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); public void ProcessRequest(HttpContext context) { String methodName = context.Request["method"]; if (!string.IsNullOrEmpty(methodName)) CallMethod(methodName, context); } /// <summary> /// 根据业务需求调用不同的方法 /// </summary> /// <param name="Method">方法</param> /// <param name="context">上下文</param> public void CallMethod(string Method, HttpContext context) { switch (Method) { case "CheckExistUserName": CheckExistUserName(context); break; case "MemberLogin": MemberLogin(context); break; case "SaveMemberInfo": SaveMemberInfo(context); break; case "CheckLoginStatus": CheckLoginStatus(context); break; case "MemberLogout": MemberLogout(context); break; default: return; } } /// <summary> /// 退出 /// </summary> /// <param name="context"></param> public void MemberLogout(HttpContext context) { string UserName = (string)context.Session["UserName"]; memberBLL bll = new memberBLL(); if (!Tools.IsNullOrEmpty(UserName)) { //如果session存在,清除session context.Session.Remove("UserName"); } //清除cookies CookieHelper.ClearCookie("UserName"); CookieHelper.ClearCookie("Pwd"); //页面跳转 JScript.AlertAndRedirect("安全退出成功!欢迎下次前来访问!", "http://www.cnblogs.com/Default.aspx"); } /// <summary> /// 检查用户登录状态 /// </summary> /// <param name="context"></param> public void CheckLoginStatus(HttpContext context) { string UserName = (string)context.Session["UserName"]; memberBLL bll = new memberBLL(); if (!Tools.IsNullOrEmpty(UserName)) { //如果session存在,直接返回用户状态 bll.WriteJsonForLogin(true, UserName); } else { //用户自动登录状态检测 context.Response.Write(bll.CheckLoginStatus()); } } /// <summary> /// 会员登录 /// </summary> /// <param name="context"></param> public void MemberLogin(HttpContext context) { try { //获取数据 string Name = context.Request["Name"]; string Pwd = context.Request["Pwd"]; string IsSaveName = context.Request["cbName"]; string IsSavePwd = context.Request["cbPwd"]; //用户登录状态 bool Status = false; //返回给客户端的json数据 string ReturnJson = ""; //sql注入检测 if (Tools.IsValidInput(ref Name, true) && (Tools.IsValidInput(ref Pwd, true)) && (Tools.IsValidInput(ref IsSaveName, true)) && (Tools.IsValidInput(ref IsSavePwd, true))) { member info = new member(); memberBLL bll = new memberBLL(); info.username = Name; info.password = Pwd; ReturnJson = bll.ReturnJson(info, out Status); if (Status) //如果成功登陆 { //记住帐号和密码 bll.RememberUserInfo(info, bll.GetRememberType(IsSaveName, IsSavePwd)); //保存登录状态 context.Session["UserName"] = info.username; } context.Response.Write(ReturnJson); } } catch (Exception ex) { logger.Error("会员登录出错!", ex); } } /// <summary> /// 验证帐号是否存在 /// </summary> /// <param name="context"></param> public void CheckExistUserName(HttpContext context) { string username = context.Request["username"]; if (Tools.IsValidInput(ref username, true)) { context.Response.Write(new memberBLL().CheckExistUserName(username)); } } /// <summary> /// 保存用户信息 /// </summary> /// <param name="context"></param> public void SaveMemberInfo(HttpContext context) { try { //表单读取 string txtUserName = context.Request["txtUserName"]; string txtPwd = context.Request["txtPwd"]; string txtEmail = context.Request["txtEmail"]; string txtCheckCode = context.Request["txtCheckCode"]; //验证码校验 if (!txtCheckCode.Equals(context.Session["checkcode"].ToString())) { return; } //字符串sql注入检测 if (Tools.IsValidInput(ref txtUserName, true) && Tools.IsValidInput(ref txtPwd, true) && Tools.IsValidInput(ref txtEmail, true)) { member info = new member(); info.username = txtUserName; info.password = txtPwd; info.Email = txtEmail; info.states = "0"; if (new memberBLL().AddNew(info) > 0) { SMTP smtp = new SMTP(info.Email); string webpath = context.Request.Url.Scheme + "://" + context.Request.Url.Authority + "/Default.aspx"; smtp.Activation(webpath, info.username);//发送激活邮件 JScript.AlertAndRedirect("注册用户成功!!", "../Default.aspx"); } else { JScript.AlertAndRedirect("注册用户失败!", "../Default.aspx"); } } } catch (Exception ex) { logger.Error("错误!", ex); } } public bool IsReusable { get { return false; } } } 业务逻辑BLL部分代码: 复制代码 代码如下: /// <summary> /// 用户登录 /// </summary> /// <param name="info">会员model</param> /// <returns></returns> public bool MemberLogin(member info) { return new memberDAL().MemberLogin(info); } /// <summary> /// 返回给客户端的json格式数据(用于根据用户登录状态决定) /// </summary> /// <param name="info"></param> /// <returns></returns> public string ReturnJson(member info, out bool Status) { //登录状态 Status = MemberLogin(info); //生成json格式数据 return WriteJsonForLogin(Status, info.username); } /// <summary> /// 记住帐号和密码的枚举 /// </summary> public enum RememberType { /// <summary> /// 记住帐号 /// </summary> RememberName = 0, /// <summary> /// 同时记住帐号和密码 /// </summary> RememberNameAndPwd = 1, /// <summary> /// 不记住帐号密码 /// </summary> NoRemember = 2 } /// <summary> /// 根据保存帐号密码状态判断是保存帐号还是同时保存帐号和密码 /// </summary> /// <param name="IsSaveName">"1"代表保存,"0"代表不保存</param> /// <param name="IsSavePwd">"1"代表保存,"0"代表不保存</param> /// <returns></returns> public RememberType GetRememberType(string IsSaveName, string IsSavePwd) { RememberType SaveType = RememberType.NoRemember; //保存帐号和密码 if (IsSaveName.Equals("1") && IsSavePwd.Equals("1")) { SaveType = RememberType.RememberNameAndPwd; } //保存帐号 if (IsSaveName.Equals("1") && !IsSavePwd.Equals("1")) { SaveType = RememberType.RememberName; } else if(!IsSaveName.Equals("1")) { SaveType = RememberType.NoRemember; } return SaveType; } /// <summary> /// 检查用户登录状态,用于验证自动登录(并返回json格式) /// </summary> /// <returns></returns> public string CheckLoginStatus() { //登录状态 bool Status = true; string UserName = Common.CookieHelper.GetCookieValue("UserName"); //如果cookies为空,直接返回 if (Tools.IsNullOrEmpty(UserName)) { Status = false; } string Pwd = Common.CookieHelper.GetCookieValue("Pwd"); if (Tools.IsNullOrEmpty(Pwd)) { Status = false; } else { //查找该用户真实密码,并进行md5加密 string password = Tools.GetMD5(new memberDAL().GetPassword(UserName)); //如果两次密码相同则可以自动登陆了 if (!password.Equals(Pwd)) { Status = false; } } //生成json格式数据 return WriteJsonForLogin(Status, UserName); } /// <summary> /// 为用户登录写入json数据 /// </summary> /// <param name="Status">登录状态</param> /// <param name="UserName">用户名</param> /// <returns></returns> public string WriteJsonForLogin(bool Status, string UserName) { StringBuilder json = new StringBuilder(); StringWriter sw = new StringWriter(json); using (JsonWriter jsonWriter = new JsonTextWriter(sw)) { jsonWriter.Formatting = Formatting.Indented; jsonWriter.WriteStartObject(); jsonWriter.WritePropertyName("Status"); jsonWriter.WriteValue(Status); jsonWriter.WritePropertyName("UserName"); jsonWriter.WriteValue(UserName); jsonWriter.WriteEndObject(); } return json.ToString(); } /// <summary> /// 记住用户信息 /// </summary> /// <param name="Type">记住用户信息类别</param> /// <returns></returns> public bool RememberUserInfo(member info, RememberType type) { if (type == RememberType.RememberName) { //记住帐号7天 CookieHelper.SetCookie("UserName", info.username, DateTime.Now.AddDays(7)); } else if (type == RememberType.RememberNameAndPwd) { //md5哈希加密 string sercret = Tools.GetMD5(info.password); //同时记住帐号和密码7天 CookieHelper.SetCookie("UserName", info.username, DateTime.Now.AddDays(7)); CookieHelper.SetCookie("Pwd", sercret, DateTime.Now.AddDays(7)); } else { return false; } return true; } 实现效果: 总结: 我们天天都在写用户登录,但是考虑安全性,复用性,却是非常少的,在这次实践过程中,Switch语句,还是一个大问题,至今除了反射没有太好的解决方法,正在考虑! 可以发现,这次的实现改进非常大,我清晰的记得去年实现这个功能的糟糕代码, 太垃圾了,代码凌乱呀…… 代码重质量,总结分析学习! 作者 cnblogs tianzh |
请发表评论