一種安全、高效、簡單的登陸算法

出處:http://dotnet.csdn.net/page/c2a65658-1671-4e07-8c46-1f099887876e#

來源:博客園

  現在微軟的vs2005中自帶的membership已經能夠很好的滿足大多數場景下的用戶管理的需求。但是某些特殊情況下我們還須要訂製的用戶登錄系統,比方說爲了效率、安全等。

  另外即使只是做做試驗也是不錯的嘗試。

  本文並沒有對各種登陸算法進行對比探討。而是僅僅給出了一個比較安全、高效也經歷了實際的考驗的算法供大家參考。

  本文中給出一個實例的節選,希望能給各位啓示。

  該算法的特點爲:

  1、安全、僅僅使用用戶名(考生號)來訪問數據庫,這樣需要控制的項就比較少了.即使進行安全檢查系統壓力也小。
  2、高效、一般情況下用戶操作僅需一次數據訪問,所需的數據就全部返回了。而且單鍵訪問數據執行效率也高。
  3、比較完整的簡單的分層設計,可以供入門程序員參考(作爲教學人員,我的註釋寫的很詳細,具有一定的可讀性)

  一、建立數據模型:數據集如下圖:存放在app_code目錄中,命名爲kaoshengs.xsd

  1、考生表的結構。依次爲考生號、考生姓名、錄取結果、密碼(口令,默認是空值。)、查分密碼(該系統中每個考生有自己的隨機查分密碼覆膜印在准考證上,第一次需要使用該密碼來登錄系統並修改密碼)、報名點代碼、縣區代碼、地市代碼(後邊3個代碼是爲了管理使用)。

  2、適配器。增加了幾個訪問數據的方法,有名稱和參數可以很容易的看出,不再解釋了。

  二、對該考生對象的操作的類庫。存放在app_code目錄中,命名爲kaosheng.cs

  需要注意的是,該系統在登陸時需要的操作比較多

1、有用戶名和密碼能夠登錄
2、有錄取結果,顯示錄取結果,並不再允許繼續操作
3、密碼爲空,則爲第一次登錄允許使用查分密碼來修改口令
4、修改已有的口令

1using System;
2using System.Data;
3using System.Configuration;
4using System.Web;
5using System.Web.Security;
6using System.Web.UI;
7using System.Web.UI.WebControls;
8using System.Web.UI.WebControls.WebParts;
9using System.Web.UI.HtmlControls;
10using System.Collections;
11
12/**//// <summary>
13/// kaosheng 的摘要說明
14/// edit by lww @2007-04-21
15/// 考生對象的相關操作
16/// </summary>
17public class kaosheng
18{
19 public kaosheng()
20 {
21 //
22 // TODO: 在此處添加構造函數邏輯
23 //
24 }
25
26 /**//// <summary>
27 /// 驗證用戶
28 /// </summary>
29 /// <param name="ksh"></param>
30 /// <param name="code"></param>
31 /// <returns>
32 /// 根據返回進行跳轉
33 /// 返回值爲arrylist 其中
34 /// retal[0]存放int形式的返回值
35 /// 其中
36 /// 0:系統出錯、數據庫連接?
37 /// 1:已被錄取
38 /// 2:登錄正確
39 /// 3:首次登錄需導向修改頁面
40 /// 4:登錄密碼不對(已有但是不正確)
41 /// 5:未更改過密碼,並且查分碼不對
42 /// 6:錯誤的考生號
43 /// retal[1]之後存放string附加值
44 /// 標號 0 1 2 3 4 5 6
45 /// 包括: 返回類型 考生號、考生姓名、縣區、 地市
46
47 /// </returns>
48 public static ArrayList yanzheng(string ksh,string code)
49 {
50 /**////根據輸入的考生號和密碼進行判斷
51 ///由於這裏需要判斷的項比較多,所以採用將考生相關信息返回的方式
52 ///根據輸入的考生號,得到返回值。包括:考生姓名、密碼、查分密碼、錄取信息
53 ArrayList ksinfo= getks(ksh);
54 ArrayList retal = new ArrayList();
55 if (ksinfo[0].ToString().Trim() == "0")
56 {//錯誤考生號
57 retal.Add("6");
58 return retal;
59 }
60 /**////1、首先判斷是否被錄取,如果被錄取則提示,不再繼續進行下面的操作
61 if ((ksinfo[4].ToString().Trim() != string.Empty) && (ksinfo[4].ToString().Trim() != null))
62 {//已經被錄取
63 retal.Add("1");
64 retal.Add(ksinfo[4].ToString());
65 return retal;
66 }
67 else
68 {//本來下邊的處理其他情況的代碼包含在else中,但是爲了程序的可讀性,我們在前邊增加了 return retal; 跳出,
69 //這樣後邊就可以從if else中剝離出來了.這裏爲了方便敘述保留了else段
70 }
71 /**////ksinfo格式
72 /// 根據考生號取得考生信息
73 /// 標號 0 1 2 3 4 5 6 7
74 /// 包括:考生號、考生姓名、密碼、查分密碼、錄取信息 縣區 地市 報名點
75
76 ///3、如果返回值密碼項不爲空,判斷是否和新輸入的密碼的md5一致,一致則允許登錄,不一致,則導向提示頁面,提示考生聯繫管理員
77 if ((ksinfo[2].ToString().Trim() != string.Empty) && (ksinfo[2].ToString().Trim() != null))
78 {
79 if (ksinfo[2].ToString().Trim() == MD5s.genmd5(code))
80 {//正確登錄
81 retal.Add("2");
82 }
83 else
84 {
85 retal.Add("4");
86 }
87 }
88 else
89 {
90 /**////4、如果爲空,判斷查分密碼是否正確,正確則導向修改密碼頁面,
91 if (ksinfo[3].ToString().Trim() == code)
92 {
93 retal.Add("3");
94 }
95 else
96 {
97 retal.Add( "5");
98 }
99 }
100 //返回結果:附加
101 retal.Add(ksinfo[0].ToString()); //考生號
102 retal.Add(ksinfo[1].ToString()); //考生姓名
103 retal.Add(ksinfo[3].ToString()); //考生登錄號
104 retal.Add(ksinfo[5].ToString()); //考生縣區名稱
105 retal.Add(ksinfo[6].ToString()); //考生地市名稱
106 retal.Add(ksinfo[7].ToString()); //報名點名稱
107 retal.Add(ksinfo[8].ToString()); //報名點代碼
108 /**//// 返回結果 
109 /// 標號 0 1 2 3 4 5 6
110 /// 包括: 代碼 考生號、考生姓名、查分密碼、 縣區 地市 報名點
111 return retal;
112 }
113 /**//// <summary>
114 /// 修改密碼:重載1、考生使用
115 /// </summary>
116 /// <param name="ksh"></param>
117 /// <param name="code"></param>
118 /// <returns></returns>
119 public static bool passchange(string ksh, string code,string newcode)
120 {
121 /**////根據考生號進行密碼重置,
122 ///首先判斷查分密碼是否正確,然後判斷更改密碼
123 ///如果密碼爲空,根據查分密碼判斷
124 ArrayList ksinfo = getks(ksh);
125 if (ksinfo[2].ToString().Trim() == string.Empty)
126 {
127 if ((ksinfo[0].ToString() == ksh) && (ksinfo[3].ToString() == code))
128 {
129 return passchange(ksh, newcode);
130 }
131 }
132 else
133 {
134 if ((ksinfo[0].ToString() == ksh) && (ksinfo[2].ToString().Trim() == MD5s.genmd5(code)))
135 {
136 return passchange(ksh, newcode);
137 }
138 }
139 return false;
140 }
141 /**//// <summary>
142 /// 重置密碼:重載2、管理員使用,將考生密碼初始化爲指定值
143 /// </summary>
144 /// <param name="ksh"></param>
145 /// <returns></returns>
146 public static bool passchange(string ksh, string newcode)
147 {
148 /**////根據考生號進行密碼重置
149 kaoshengsTableAdapters.tksTableAdapter ksapt = new kaoshengsTableAdapters.tksTableAdapter();
150 string newpass = "";
151 //邏輯,置空密碼傳入的時候需要處理,不需要md5
152 if(newcode.Trim()==string.Empty)
153 {
154 newpass = "";
155 }
156 else
157 {
158 newpass = MD5s.genmd5(newcode);
159 }
160 try
161 {
162 ksapt.passchange(newpass, ksh);
163 return true;
164 }
165 catch { return false; }
166 }
167
168 /**//// <summary>
169 /// 登錄日誌
170 /// </summary>
171 /// <param name="ksh"></param>
172 /// <param name="code"></param>
173 /// <returns></returns>
174 public static string loginlog(string ksh, string ip,string code)
175 {
176 /**////寫日誌
177 rizhiTableAdapters.rzTableAdapter rz = new rizhiTableAdapters.rzTableAdapter();
178 rz.rizhi(ksh, ip, code);
179    return "ok";
180 }
181
182 /**//// <summary>
183 /// 根據考生號取得考生信息
184 /// 請注意,該命令僅僅使用ksh作爲參數而沒有使用用戶名,
185 /// 原因爲
186 /// 1、安全:ksh已經在網頁中限制爲僅能爲數字
187 /// 2、高效:數字的主鍵訪問速度快
188 /// 返回信息爲: ///
189 /// 標號 0 1 2 3 4 5 6 7 8
190 /// 包括:考生號、考生姓名、密碼、查分密碼、錄取信息 縣區 地市 報名點 報名點代碼
191 /// </summary>
192 /// <param name="ksh"></param>
193 public static ArrayList getks(string ksh)
194 {
195 /**////從數據庫中根據考生號填充數據然後將arraylist填充
196 kaoshengsTableAdapters.tksTableAdapter ksapt = new kaoshengsTableAdapters.tksTableAdapter();
197 kaoshengs.tksDataTable tks=new kaoshengs.tksDataTable();
198 ksapt.getksinfo(tks, ksh);
199 kaoshengs.tksRow r = tks.FindByksh(ksh);
200 ArrayList al = new ArrayList();
201 if (r==null)
202 {//未發現記錄,返回第一個爲"0"標記爲錯誤
203 al.Add("0");
204 return al;
205 }
206 else
207 {
208 al.Add(r.ksh.ToString().Trim()); //考生考生號
209 al.Add(r.ksxm.ToString().Trim()); //考生姓名
210 al.Add(r.mima.ToString().Trim()); //考生當前密碼
211 al.Add(r.kscf.ToString().Trim()); //考生查分密碼
212 al.Add(r.kslq.ToString().Trim()); //考生是否被錄取
213 /**////在這裏返回的區域代碼需要翻譯爲含義
214 string xqdm = r.bmddm.Substring(0, 4).Trim();
215 string dsdm = r.bmddm.Substring(0, 2).Trim();
216 string bmddm = r.bmddm.Substring(0,6).Trim();
217 string xqmc = cache.transxqdm(xqdm);
218 string dsmc = cache.transdsdm(dsdm);
219 string bmdmc = cache.transbmddm(bmddm);
220 al.Add(xqmc); //縣區名稱
221 al.Add(dsmc); //地市名稱
222 al.Add(bmdmc); //報名點名稱
223 al.Add(r.bmddm.Substring(0, 6).Trim()); //報名點代碼
224 return al;
225 }
226 }
227
228 //下邊的代碼爲管理員使用的部分
229
230 /**//// <summary>
231 /// 通過考生號加載數據
232 /// </summary>
233 /// <param name="ksh"></param>
234 /// <returns></returns>
235 public static kaoshengs.tksDataTable getbyksh(string ksh)
236 {
237 //首先取出當前的權限
238 ArrayList alqx = quanxian.yanzheng();
239 kaoshengs.tksDataTable tb = new kaoshengs.tksDataTable();
240 kaoshengsTableAdapters.tksTableAdapter ksapt = new kaoshengsTableAdapters.tksTableAdapter();
241 tb = ksapt.GetDataByksh(ksh, alqx[3].ToString(), alqx[4].ToString());
242 return tb;
243 }
244 /**//// <summary>
245 /// 通過考生姓名加載數據,模糊查詢
246 /// </summary>
247 /// <param name="ksxm"></param>
248 /// <returns></returns>
249 public static kaoshengs.tksDataTable getbyxm(string ksxm)
250 {
251 //首先取出當前的權限
252 ArrayList alqx = quanxian.yanzheng();
253 kaoshengs.tksDataTable tb = new kaoshengs.tksDataTable();
254 kaoshengsTableAdapters.tksTableAdapter ksapt = new kaoshengsTableAdapters.tksTableAdapter();
255 tb = ksapt.GetDataByxm(ksxm, alqx[3].ToString(), alqx[4].ToString());
256 return tb;
257 }
258
259 /**//// <summary>
260 /// 通過考生號範圍加載數據
261 /// </summary>
262 /// <param name="kshmin"></param>
263 /// <param name="kshmax"></param>
264 /// <returns></returns>
265 public static kaoshengs.tksDataTable getbyfw(string kshmin,string kshmax)
266 {
267 //首先取出當前的權限
268 //ArrayList alqx = quanxian.yanzheng();
269 /**/////將用戶輸入的範圍置入當前權限允許的範圍內
270 string min=kshmin,max=kshmax;
271 ArrayList alqx = quanxian.yanzheng();
272 if (Convert.ToInt64(kshmin) < Convert.ToInt64(alqx[3].ToString()))
273 { min = alqx[3].ToString(); }
274 if (Convert.ToInt64(kshmax) > Convert.ToInt64(alqx[4].ToString()))
275 { max = alqx[4].ToString(); }
276 kaoshengs.tksDataTable tb = new kaoshengs.tksDataTable();
277 kaoshengsTableAdapters.tksTableAdapter ksapt = new kaoshengsTableAdapters.tksTableAdapter();
278 tb = ksapt.GetDataByfw(min, max);
279 return tb;
280 }
281
282
283}

  三、登錄頁面。頁面如下,其中考生號有ajax效果控制不能輸入除數字以外的信息

  下邊的該頁的後臺代碼,爲節省篇幅,僅給出進入系統按紐的代碼如下:
需要注意的是因爲引入了ajax所以輸出提示信息的方式和以前不一樣了.

1 protected void btlogin_Click(object sender, EventArgs e)
2 {
3 /**////取值
4 string ksh = this.tbksh.Text.Trim();
5 string code = this.tbcode.Text.Trim();
6 string yanzheng = this.tbyanzheng.Text.Trim();
7 /**////判斷驗證碼
8 //提示彈出對話框需要註冊客戶端腳本
9 ClientScriptManager csm = this.ClientScript;
10
11 if (tbyanzheng.Text.ToLower() == quanxian.yanzhengcode())
12 {
13 /**////判斷用戶
14 ArrayList retal = kaosheng.yanzheng(ksh, code);
15 /**////根據返回進行跳轉
16 ///返回值爲arrylist 其中
17 /// retal[0]存放int形式的返回值
18 /// 其中
19 /// 0:系統出錯、數據庫連接?
20 /// 1:已被錄取
21 /// 2:登錄正確
22 /// 3:首次登錄需導向修改頁面
23 /// 4:登錄密碼不對(已有但是不正確)
24 /// 5:未更改過密碼,並且查分碼不對
25 int backcode = Convert.ToInt16(retal[0].ToString().Trim());
26 if (backcode == 3 || backcode == 2)
27 {
28 string strip = Request.UserHostAddress;
29 kaosheng.loginlog(ksh, strip, backcode.ToString());
30
31 }
32 if (backcode == 0)
33 {
34 csm.RegisterStartupScript(this.GetType(), "Hello", "<script>alert('服務器忙,或數據連接錯,請聯繫管理員!')</script>");
35 }
36 if (backcode == 1)
37 {
38 csm.RegisterStartupScript(this.GetType(), "Hello", "<script>alert('你已經被《" + retal[1].ToString() + "》錄取,不能再填報其他志願!')</script>");
39 }
40 if (backcode == 2)
41 {
42 //登錄正確,首先準備參數數組,然後傳遞
43 retal[0] = "0"; //標記爲0代表爲考生信息
44 /**////此時retal中存放
45 /// 標號 0 1 2 3 4 5 6 7
46 /// 包括: 0 考生號、考生姓名、 登錄號 縣區 地市 報名點 報名點代碼
47 quanxian.buildsession(retal);
48 Response.Redirect("kszy.aspx");
49
50 }
51 if (backcode == 3)
52 {
53 //首先準備,參數,包括 ksh,name、查分、縣區、地市
54 /**////此時retal中存放
55 /// 標號 0 1 2 3 4 5。。。
56 /// 包括: 3 考生號、考生姓名、 登錄號 縣區 地市。。。
57
58 //調用靜態方法將數據放入session中。
59 if(quanxian.buildsession(retal)) Response.Redirect("passchange.aspx");
60 }
61 if (backcode == 4)
62 {
63 csm.RegisterStartupScript(this.GetType(), "Hello", "<script>alert('密碼不正確,請聯繫管理員!')</script>");
64 }
65 if (backcode == 5)
66 {
67 csm.RegisterStartupScript(this.GetType(), "Hello", "<script>alert('查分密碼不正確,請聯繫管理員!')</script>");
68 }
69 if (backcode == 6)
70 {
71 csm.RegisterStartupScript(this.GetType(), "Hello", "<script>alert('考生號輸入不正確,本次操作已經被記錄,請認真核對!')</script>");
72 }
73 /**////1、導向修改密碼
74 ///2、導向填報頁面
75
76 }
77 else
78 {
79 //不相同則提示錯誤信息
80 csm.RegisterStartupScript(this.GetType(), "Hello", "<script>alert('必須輸入正確的驗證碼!')</script>");
81 }
82 }

  登錄程序到這裏就完成了. 
發佈了2 篇原創文章 · 獲贊 0 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章