当前位置: 移动技术网 > IT编程>开发语言>.net > 一步一步学asp.net Ajax登录设计实现解析

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

2017年12月12日  | 移动技术网IT编程  | 我要评论

半推半就的以文,英国牙医虎口拔牙,卫浴装修

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

这是前台页面,要求实现用户登录
clip_image002
首先我们分析,

用户需求:

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;
}

实现效果:
clip_image004

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网