任務需求:做一個登錄,擁有自動記住賬號和密碼的功能,要保證安全性,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