运用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 SqlHelper

11     {

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             else

112             {

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 : INotifyPropertyChanged

122     {

123         private string loginInfo;

124         public string LoginInfo

125         {

126             get { return loginInfo; }

127             set

128             {

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                    bigint

2 //UserName       nvchar(20)   

3 //PassWord       nvchar(20)    

4 //Frequency       int

5 //ErrorTime        datetime
View Code

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

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

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

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

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

你可能感兴趣的:(.net)