项目文件列表:
GetUserLoginState.sc
public class GetUserLoginState { /// <summary> /// 检测用户登录状态 /// </summary> public GetUserLoginState() { } //推荐在此定义类型变量,而不是在方法中new一个新的对象 private TLoginModel model; public UserLoginStateEnum LoginState(string userName, string password, out int ID) { TLoginDataManager manager = new TLoginDataManager(); ID = -1;//这里是的编写思想一个亮点 model = manager.GetUserLoginInfo(userName); if (model != null) { if (model.LockTime == null || DateTime.Compare((DateTime)model.LockTime, DateTime.Now) < 0) { if (model.ErrorTimes == null || model.ErrorTimes < 4)//帐户锁定情况判断 { MD5Encrypt md5 = new MD5Encrypt(); if (model.MD5Password == md5.Encryption(password)) { ID = model.ID; return UserLoginStateEnum.LoginSucceed; } else { manager.RaiseErrorTimes(model.ID); return UserLoginStateEnum.PasswordError; } } } //这里你有疑问吗? manager.LockUser(model.ID); return UserLoginStateEnum.LoginFailed; } else { return UserLoginStateEnum.NoUserName; } } public int ChangePassword(string pwd, int id) { TLoginDataManager manager = new TLoginDataManager(); MD5Encrypt md5 = new MD5Encrypt(); return manager.PasswordChange(md5.Encryption(pwd), id); } public bool VerifyPassword(string pwd, int id) { TLoginDataManager manager = new TLoginDataManager(); MD5Encrypt md5 = new MD5Encrypt(); return manager.VerifyPassword(md5.Encryption(pwd), id); } }
MD5Encrypt.cs
public class MD5Encrypt { /// <summary> /// 计算字符串 str 的HashValue /// </summary> /// <param name="str">字符串</param> /// <returns>返回 str 的32位HashValue</returns> public string Encryption(string str) { byte[] strByte = Encoding.UTF8.GetBytes(str); MD5 md5 = MD5.Create(); strByte = md5.ComputeHash(strByte); md5.Clear(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < strByte.Length; i++) { sb.Append(strByte[i].ToString("x2")); } return sb.ToString(); } }
UserLoginStateEnum.cs
/// <summary> /// 表示用户登录状态 /// </summary> public enum UserLoginStateEnum { NoUserName, PasswordError, LoginFailed, LoginSucceed }
SqlHelper.cs
public class SqlHelper { /// <summary> /// 数据查询帮助类 /// </summary> public SqlHelper() { } private string constr = ConfigurationManager.ConnectionStrings["sql"].ConnectionString; /// <summary> /// 对连接执行 Transact-SQL 语句并返回受影响的行数。 /// </summary> /// <param name="sql">Transact-SQL 更新语句</param> /// <param name="param">参数</param> /// <returns>受影响的行数。</returns> public int ExecuteNonQuery(string sql, params SqlParameter[] param) { using (SqlConnection con = new SqlConnection(constr)) { using (SqlCommand cmd = new SqlCommand(sql, con)) { if (param != null) { cmd.Parameters.AddRange(param); } con.Open(); return cmd.ExecuteNonQuery(); } } } /// <summary> /// 将 System.Data.SqlClient.SqlCommand.CommandText 发送到 System.Data.SqlClient.SqlCommand.Connection,并使用 /// System.Data.CommandBehavior 值之一生成一个 System.Data.SqlClient.SqlDataReader。 /// </summary> /// <param name="sql">Transact-SQL 查询语句</param> /// <param name="param">参数</param> /// <returns>System.Data.SqlClient.SqlDataReader 对象。</returns> public SqlDataReader ExecuteReader(string sql, params SqlParameter[] param) { SqlConnection con = new SqlConnection(constr); try { using (SqlCommand cmd = new SqlCommand(sql, con)) { if (param != null) { cmd.Parameters.AddRange(param); } con.Open(); return cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection); } } catch (Exception)//模拟using(SqlConnection con = new SqlConnection(constr)) { con.Close(); con.Dispose(); throw; } } /// <summary> /// 执行查询,并返回查询所返回的结果集中第一行的第一列。 忽略其他列或行。 /// </summary> /// <param name="sql">Transact-SQL 查询语句</param> /// <param name="param">参数</param> /// <returns>结果集中第一行的第一列;如果结果集为空,则为空引用(在 Visual Basic 中为 Nothing)。 返回的最大字符数为 2033 个字符。</returns> public object ExecuteScalar(string sql, params SqlParameter[] param) { using (SqlConnection con = new SqlConnection(constr)) { using (SqlCommand cmd = new SqlCommand(sql, con)) { if (param != null) { cmd.Parameters.AddRange(param); } con.Open(); return cmd.ExecuteScalar(); } } } /// <summary> /// 执行查询,并返回查询所返回的结果集 /// </summary> /// <param name="sql">Transact-SQL 查询语句</param> /// <param name="param">参数</param> /// <returns>System.Data.DataTable 对象</returns> public DataTable ExecuteDataTable(string sql, params SqlParameter[] param) { DataTable dt = new DataTable(); using (SqlDataAdapter adapter = new SqlDataAdapter(sql, constr)) { if (param != null) { adapter.SelectCommand.Parameters.AddRange(param); } adapter.Fill(dt); } return dt; } }
TLoginDataManager.cs
public class TLoginDataManager { /// <summary> /// 对Login表的数据管理 /// </summary> public TLoginDataManager() { } public TLoginModel GetUserLoginInfo(string userName) { SqlHelper sqlhelper = new SqlHelper(); string sql = "select * from MD5Login where name=@userName"; using (SqlDataReader reader = sqlhelper.ExecuteReader(sql, new SqlParameter("@userName", userName))) { if (reader.HasRows) { try { TLoginModel userModel = new TLoginModel(); while (reader.Read()) { userModel.ID = int.Parse(reader[0].ToString()); userModel.Name = reader[1].ToString(); userModel.MD5Password = reader[2].ToString(); //(int)值类型 null 是不可能的:所以要做强制类型转换 userModel.ErrorTimes = reader.IsDBNull(3) ? null : (int?)int.Parse(reader[3].ToString()); userModel.LockTime = reader.IsDBNull(4) ? null : (DateTime?)DateTime.Parse(reader[4].ToString()); userModel.Place = reader[5].ToString(); } //读一行可以这样写:读多行时就用List<T>集合。 return userModel; } catch (Exception) { throw; } } } //这样做于利于弊,自己权衡吧。 return null; } internal void LockUser(int p) { SqlHelper sqlhelper = new SqlHelper(); string sql = "update MD5Login set locktime=dateadd(minute,10,getdate()),errortimes=0 where id=@id"; sqlhelper.ExecuteNonQuery(sql, new SqlParameter("@id", p)); } internal void RaiseErrorTimes(int p) { SqlHelper sqlhelper = new SqlHelper(); string sql = "update MD5Login set errortimes=errortimes+1 where id=@id"; sqlhelper.ExecuteNonQuery(sql, new SqlParameter("@id", p)); } public int PasswordChange(string pwd, int id) { SqlHelper sqlhelper = new SqlHelper(); string sql = "update MD5Login set MD5pwd=@pwd where id=@id"; return sqlhelper.ExecuteNonQuery(sql, new SqlParameter("@pwd", pwd), new SqlParameter("@id", id)); } internal bool VerifyPassword(string p, int id) { SqlHelper sqlhelper = new SqlHelper(); string sql = "select * from MD5Login where id=@id and MD5pwd=@pwd"; return sqlhelper.ExecuteReader(sql, new SqlParameter("@id", id), new SqlParameter("@pwd", p)).HasRows; } }
TLoginModel.cs
public class TLoginModel { /// <summary> /// Login表数据模板类 /// </summary> public TLoginModel() { } /// <summary> /// 用户id /// </summary> public int ID { get; set; } /// <summary> /// 用户名称 /// </summary> public string Name { get; set; } //用不用储存密码? /// <summary> /// 用户密码的MD5值 /// </summary> public string MD5Password { get; set; } /// <summary> /// 登录错误次数 /// int? 表示int的可空类型(Nullable) /// </summary> public int? ErrorTimes { get; set; } /// <summary> /// 帐户锁定时间 /// DateTime? 表示DateTime的可空类型(Nullable) /// </summary> public DateTime? LockTime { get; set; } /// <summary> /// 登录地点 /// </summary> public string Place { get; set; } /// string? :错误的!!值类型 are nullable not }
UserCurrentID.cs
public static class UserCurrentID { public static int ID { get; set; } }
frmLogin类
public partial class frmLogin : Form { public frmLogin() { InitializeComponent(); } private UserLoginStateEnum state; private void btnLogin_Click(object sender, EventArgs e) { GetUserLoginState login = new GetUserLoginState(); string name = txtUserName.Text.Trim(); string password = txtPassword.Text.Trim(); //在这里有UI的BLL,当然也可以写在BLL中 //判断输入框不能为空的情况。 //属性、索引器或动态成员访问不得作为 out 或 ref 参数传递 //state = login.LoginState(name, password, out UserCurrentID.ID); int ID; state = login.LoginState(name, password, out ID); if (state == UserLoginStateEnum.LoginSucceed) { UserCurrentID.ID = ID; MessageBox.Show("登录成功"); this.btnPasswordChange.Enabled = true; } else if (state == UserLoginStateEnum.NoUserName) { MessageBox.Show("用户不存在"); } else if (state == UserLoginStateEnum.PasswordError) { MessageBox.Show("密码错误"); } else if (state == UserLoginStateEnum.LoginFailed) { MessageBox.Show("错误次数过多,锁定10分钟,稍后再试。"); } } private void btnPasswordChange_Click(object sender, EventArgs e) { PasswordChange changePwd = new PasswordChange(); changePwd.Show(); } }
PasswordChange类
public partial class PasswordChange : Form { public PasswordChange() { InitializeComponent(); } private void btnCancel_Click(object sender, EventArgs e) { this.Dispose(); } private void btnOK_Click(object sender, EventArgs e) { GetUserLoginState state = new GetUserLoginState(); //这里便是UI层的BLL, //当然也可以在BLL中设计(和登录状态类似的设计) if (state.VerifyPassword(txtOriginalPassword.Text.Trim(), UserCurrentID.ID)) { if (txtNewPassword.Text.Trim() == txtVerifyNewPassword.Text.Trim()) { state.ChangePassword(txtVerifyNewPassword.Text.Trim(), UserCurrentID.ID); MessageBox.Show("密码修改成功"); } else MessageBox.Show("两次密码不一致"); } else MessageBox.Show("原密码错误"); } }