一步一步学asp.net Ajax登录设计实现解析

时间:2021-12-07 06:18:29

任务需求:做一个登录,拥有自动记住账号和密码的功能,要保证安全性,ajax,无刷新,良好的用户体验.(母板页) 

这是前台页面,要求实现用户登录 
一步一步学asp.net 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")%>' /> 接下来,后台相应请求: 

复制代码代码如下:


<%@ 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; 


实现效果: 
一步一步学asp.net Ajax登录设计实现解析

总结: 
我们天天都在写用户登录,但是考虑安全性,复用性,却是非常少的,在这次实践过程中,Switch语句,还是一个大问题,至今除了反射没有太好的解决方法,正在考虑! 
可以发现,这次的实现改进非常大,我清晰的记得去年实现这个功能的糟糕代码, 太垃圾了,代码凌乱呀…… 
代码重质量,总结分析学习!
一步一步学asp.net Ajax登录设计实现解析