这一篇,我们用之前学习过的知识,做一个用户登陆的案例。
1. 需求分析
用户界面中进行登录判断。输错三次禁止登陆(半小时),用数据库记录ErrorTimes。
在客户端要求登陆的时候,我们需要将用户名和密码进行验证,如果输错密码的次数达到3次,就禁止用户在半小时内登陆。于是,我们就需要在数据库中记录下用户被禁止登陆的时间。如果输错密码的次数达到了3次,就判断距离禁止登陆的时间是否超过了半个小时;如果超过了,就允许用户登陆。
2. 设计表
建立用户表 t_user
ErrorTimes 用户输错密码的次数 int类型; LastLockTime datetime类型 上一次用户被禁止登陆的时间
数据库里,建表的时候要设计id这一列,一般来说都是将id设置为主键,这是一个很好的编程习惯。因为根据id来操作数据会更安全。
3. 程序逻辑
(1)确保用户名和密码不为空
(2)把用户输入
(3) 判断用户输出密码的次数是否达到3次。小宇3次,用户可以登陆。如果达到了3次,就判断现在的时间距离上一次被禁的时间有多长,如果达到了30分钟,就需要将用户输错密码的次数清零,让用户可以登陆;如果不超过30分钟,就不允许用户登陆。
4. 程序代码
1 if (tBoxUserName.Text.Length <= 0) 2 { 3 MessageBox.Show("用户名不能为空"); 4 return; 5 } 6 if (tBoxPassWord.Text.Length <= 0) 7 { 8 MessageBox.Show("密码不能为空"); 9 return; 10 }
1 DataSet dataSet = SQLHelper.ExecuteDataSet("select * from t_user where [email protected]", 2 new SqlParameter("@userName", tBoxUserName.Text)); 3 DataTable table = dataSet.Tables[0]; 4 //编程的时候,我们要对认为不能发生的情况进行处理 5 if (table.Rows.Count <= 0) 6 { 7 MessageBox.Show("用户名不存在"); 8 return; 9 } 10 11 //防御性编程 12 if (table.Rows.Count > 1) 13 { 14 MessageBox.Show("用户名重复"); 15 return; 16 }
1 DataRow row = table.Rows[0]; 2 long id = (long)row["Id"]; 3 string userName = (string)row["UserName"]; 4 string passWord = (string)row["PassWord"]; 5 int errorTimes = (int)row["ErrorTimes"]; 6 7 if (errorTimes >= 3) 8 { 9 if (row["LastLockTime"] != null) 10 { 11 DateTime lastLockTime = Convert.ToDateTime(row["LastLockTime"]); 12 //计算时间间隔 13 TimeSpan timeSpan = DateTime.Now - lastLockTime; 14 if (timeSpan >= TimeSpan.FromMinutes(30)) //将30分钟转换成时间间隔的形式 15 { //30分钟后,解除账号登陆的锁定 16 SQLHelper.ExecuteNoQuery("Update t_user set ErrorTimes = 0 where Id = @id", 17 new SqlParameter("@id", id)); 18 errorTimes = 0; 19 } 20 else 21 { 22 MessageBox.Show("你的账号已被锁定!"); 23 return; 24 } 25 } 26 else 27 { 28 MessageBox.Show("你的账号已被锁定!"); 29 return; 30 } 31 }
if (passWord != tBoxPassWord.Text) { MessageBox.Show("密码不正确!"); SQLHelper.ExecuteNoQuery("Update t_user set ErrorTimes = ErrorTimes + 1 where [email protected]", new SqlParameter("@id",id)); //第3次密码错误的时候,将出错的时间写入数据库 if (errorTimes >= 2) //之前已经出错2次 { SQLHelper.ExecuteNoQuery("Update t_user set LastLockTime = @lockTime where [email protected]", new SqlParameter("@lockTime",System.DateTime.Now), new SqlParameter("@id",id)); } return; } else { MessageBox.Show("登陆成功!"); return; }
5. datetime类型
LastLockTime 这个字段是datetime类型,在程序中进行转换的时候,我们需要将它转换成C#中的DateTime类型,注意DateTime是一个结构体,不能象int类型那样使用(int)来进行强制转换。正确的转换方法:DateTime lastLockTime = Convert.ToDateTime(row["LastLockTime"]);
6. 防御性编程
或消除墨菲定律效力。毕竟,人总是难免会犯错;任何小概率的事件都有可能会发生;在程序中,BUG经常出现在我们认为不可能发生的事情点上。
所以在程序中,我们需要先设计号程序的流程,把会发生的可能性考虑进去,设立多重关卡,来杜绝BUG的产生。
在上面的代码中,如果 table.Rows.Count 等于 0的时候,用户名是不存在的。通常会写成if (table.Rows.Count == 0),因为我们认为table.Rows.Count不可能为0,但在程序运行的时候,难免会有意外的情况出现,有可能因为某个意外,table.Rows.Count的值变成了负数,有可能会造成灾难性的结果。 所以if (table.Rows.Count <= 0) 这样的写法会更为安全。不管是做什么,还是安全第一。