一种安全、高效、简单的登陆算法

出处: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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章