首页 > 代码库 > 运用WPF和ADO.Net实现限制登录错误次数的简单登录界面

运用WPF和ADO.Net实现限制登录错误次数的简单登录界面

  最近看了一下传智播客的免费公开课视频,有一个登录界面的小练习。其中涉及到登录时间的限定功能,并未实现。所以我就自己动手写了一个,大家可以看看。

首先编写SqlHelper类,通过SqlHelper类实现SQL单语句操作数据库。代码如下:

 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Data.SqlClient; 6 using System.Data; 7  8 namespace 登录界面 9 {10     class SqlHelper11     {12         //此处没有设置为App.Config文件里的配置,只是想简单实现本项目。13         private static string connectStr = @"Data Source=.\SQLEXPRESS;Initial Catalog=JJLogin;Integrated Security=True;";14 15         public static void ExecuteNonQuery(string sql, params SqlParameter[] parameters)16         {17             using (SqlConnection conn = new SqlConnection(connectStr))18             {19                 conn.Open();20                 using (SqlCommand cmd = conn.CreateCommand())21                 {22                     cmd.CommandText = sql;23                     cmd.Parameters.AddRange(parameters);24                     cmd.ExecuteNonQuery();25                 }26             }27         }28 29         public static object ExecuteScalar(string sql, params SqlParameter[] parameters)30         {31             using (SqlConnection conn = new SqlConnection(connectStr))32             {33                 conn.Open();34                 using (SqlCommand cmd = conn.CreateCommand())35                 {36                     cmd.CommandText = sql;37                     cmd.Parameters.AddRange(parameters);38                     object obj = cmd.ExecuteScalar();39                     return obj;40                 }41             }42         }43 44         public static DataTable ExecuteDataTable(string sql, params SqlParameter[] parameters)45         {46             using (SqlConnection conn = new SqlConnection(connectStr))47             {48                 conn.Open();49                 using (SqlCommand cmd =conn.CreateCommand())50                 {51                     cmd.CommandText = sql;52                     cmd.Parameters.AddRange(parameters);53                     SqlDataAdapter adapter = new SqlDataAdapter(cmd);54                     DataTable ds = new DataTable();55                     adapter.Fill(ds);56                     return ds;57                 }58             }59         }60     }61 }
View Code

  因最近半个月都在学习WPF技术,所以本示例采用的是WPF显示层技术。XAML代码如下:

 1 <Window x:Class="登录界面.MainWindow" 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4         Title="微博登录" Height="200" Width="250" ResizeMode="NoResize"> 5     <Grid> 6         <Grid.RowDefinitions> 7             <RowDefinition Height="Auto"></RowDefinition> 8             <RowDefinition Height="Auto"></RowDefinition> 9             <RowDefinition Height="Auto"></RowDefinition>10             <RowDefinition Height="*"></RowDefinition>11         </Grid.RowDefinitions>12         <Grid.ColumnDefinitions>13             <ColumnDefinition Width="Auto"></ColumnDefinition>14             <ColumnDefinition Width="*"></ColumnDefinition>15             <ColumnDefinition Width="Auto"></ColumnDefinition>16         </Grid.ColumnDefinitions>17         <TextBlock Grid.Row="0" Grid.Column="0" Text="用户名"></TextBlock>18         <TextBlock Grid.Row="1" Grid.Column="0" Text="密码"></TextBlock>19         <TextBox x:Name="txt_UserName" Grid.Row="0" Grid.Column="1" Margin="3"></TextBox>20         <PasswordBox x:Name="txt_PassWord" Grid.Row="1" Grid.Column="1" Margin="3"></PasswordBox>21         <DockPanel x:Name="btndock_login" Grid.Row="2" Grid.Column="1" Margin="3" Button.Click="btndock_login_Click">22             <Button x:Name="btn_loginIn" Content="登录" HorizontalAlignment="Left" Margin="3"></Button>23             <Button x:Name="btn_loginOut" Content="取消" HorizontalAlignment="Right" Margin="3"></Button>24         </DockPanel>25         <TextBlock x:Name="tbk_LoginMessage" Grid.Row="3" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Stretch" TextWrapping="Wrap"></TextBlock>26     </Grid>27 </Window>
View Code

  逻辑层代码如下:

  1 using System;  2 using System.Collections.Generic;  3 using System.Linq;  4 using System.Text;  5 using System.Windows;  6 using System.Windows.Controls;  7 using System.Windows.Data;  8 using System.Windows.Documents;  9 using System.Windows.Input; 10 using System.Windows.Media; 11 using System.Windows.Media.Imaging; 12 using System.Windows.Navigation; 13 using System.Windows.Shapes; 14 using System.Data.SqlClient; 15 using System.Data; 16 using System.ComponentModel; 17  18 namespace 登录界面 19 { 20     /// <summary> 21     /// MainWindow.xaml 的交互逻辑 22     /// </summary> 23     public partial class MainWindow : Window 24     { 25         private Message message; 26         public MainWindow() 27         { 28             InitializeComponent(); 29  30             message = new Message(); 31             tbk_LoginMessage.SetBinding(TextBlock.TextProperty, new Binding("LoginInfo") { Source = message }); 32         } 33  34         private void btndock_login_Click(object sender, RoutedEventArgs e) 35         { 36             if (e.OriginalSource is Button) 37             { 38                 switch (((Button)e.OriginalSource).Name) 39                 { 40                     case "btn_loginIn": 41                         { 42                             LoginIn(txt_UserName.Text, txt_PassWord.Password); 43                         } break; 44                     case "btn_loginOut": 45                         { 46                             txt_UserName.Text = string.Empty; 47                             txt_PassWord.Password = string.Empty; 48                         } 49                         break; 50                     default: break; 51                 } 52             } 53             else 54             { 55                 throw new Exception("请点击登录或取消按钮"); 56             } 57         } 58  59         private void LoginIn(string userName, string password) 60         { 61             //查询SQLServer默认情况下不区分大小写,因此对于用户名需要采取区分大小写的查询方式,此程序有待升级 62             string sqlSelect = "select * from T_User where UserName=@UserName"; 63             DataTable table = SqlHelper.ExecuteDataTable(sqlSelect, new SqlParameter("@UserName", txt_UserName.Text)); 64             int count = table.Rows.Count; 65             if (count <= 0) 66             { 67                 message.LoginInfo = "用户不存在"; 68                 return; 69             } 70             else if (count > 1) 71             { 72                 message.LoginInfo = "不好啦,用户名重复啦"; 73                 return; 74             } 75             DataRow row = table.Rows[0]; 76             long id = (long)row["ID"]; 77             string dbPassword = (string)row["PassWord"]; 78             int frequency = (int)row["Frequency"]; 79             DateTime dbTime = (DateTime)row["ErrorTime"]; 80             if (frequency >= 3) 81             { 82                 //如果frequency>=4就会比较dbTime与DateTime.Now之间的时间间隔是否大于15s 83                 if (frequency >= 4) 84                 { 85                     TimeSpan timespan = DateTime.Now - dbTime; 86                     double d = timespan.TotalSeconds; 87                     if (d < 15.0) 88                     { 89                         message.LoginInfo = "请15s后再来登陆"; 90                         return; 91                     } 92                     //只要超过15s间隔再登陆就应该设置错误次数=0 93                     frequency = 0; 94                     goto passwordValidate; 95                 } 96  97                 string sqlUpdateErrorTime = "Update T_User set ErrorTime=@ErrorTime,Frequency=@Frequency+1"; 98                 SqlHelper.ExecuteNonQuery(sqlUpdateErrorTime, new SqlParameter("@ErrorTime", DateTime.Now), new SqlParameter("@Frequency", frequency)); 99                 message.LoginInfo = "输入错误次数太多,请耐心等待15s后再登陆";100                 return;101             }102 103         passwordValidate:104             if (dbPassword != password)105             {106                 string sqlUpdateFrequency = "Update T_User set Frequency=@Frequency+1";107                 SqlHelper.ExecuteNonQuery(sqlUpdateFrequency, new SqlParameter("@Frequency", frequency));108                 message.LoginInfo = "密码输入错误"+(frequency+1)+"";109                 return;110             }111             else112             {113                 frequency = 0;114                 string sqlUpdateFrequency = "Update T_User set Frequency=@Frequency";115                 SqlHelper.ExecuteNonQuery(sqlUpdateFrequency, new SqlParameter("@Frequency", frequency));116                 message.LoginInfo = "登陆成功";117             }118         }119     }120 121     public class Message : INotifyPropertyChanged122     {123         private string loginInfo;124         public string LoginInfo125         {126             get { return loginInfo; }127             set128             {129                 loginInfo = value;130                 if (PropertyChanged != null)131                 {132                     PropertyChanged(this, new PropertyChangedEventArgs("LoginInfo"));133                 }134             }135         }136 137         public event PropertyChangedEventHandler PropertyChanged;138     }139 }
View Code

  数据库设计:

1 //ID                    bigint2 //UserName       nvchar(20)   3 //PassWord       nvchar(20)    4 //Frequency       int5 //ErrorTime        datetime
View Code

  关于登录时间的处理,本示例的思路是:如果连续三次登录错误,就会将当前系统时间存进数据库,但是输入错误次数(frequency)不清零。当你再次尝试登录时,会从数据库中读出本用户上次错误登录时的时间,将该值与现在的系统时间进行比较,如果小于规定的时间间隔,则提示用户耐心等待。如果时间间隔(timespan)大于规定的时间间隔,则将错误登录次数清零,接着进行经常的密码验证流程。

  本示例是一个简单版本,当然会有很多考虑不周到的地方。目前的不足:

  1.数据库查询如何进行大小写敏感设置,目前我还不会如何设置,所以数据库中的用户名输入大小写都能登录成功,这个肯定要改。

  2.因为是用WPF做的界面,所以关于登录信息提示的TextBlock,其文本属性应该绑定到Message消息中,所以可设置一个Message类,将提示信息文本保存在Message类的LoginInfo属性中。但是用户名和密码等输入文本框也应该以Mode=OneWayToSource绑定到User类的UserName与Password属性中。并对输入的数据进行Validation,通过自定义UserNameValidationRule和PasswordValidationRule。这些细节目前还没完全实现,正在编码中。在接下来的WPF学习中会继续研究。

  最后,大家如有好的意见可以留言。

运用WPF和ADO.Net实现限制登录错误次数的简单登录界面