阅读目录:
5. 数据库初始连接方式(即用即开)——查询1:验证用户名密码是否匹配
6. 数据库操作方式——查询2:通过用户名获取雇员姓名和职务
如果你是第一次听说或者接触Visual studio,那么启动的时候会遇到这样的界面。
本教程是用C#编程语言。VisualStudio还可以支持很多其他的编程语言,比如VisualBasic、C++、C,更牛的是还支持J#(也就是可以编写java语言)。启动后如果要求输入序列号,请输入 YCFHQ-9DWCY-DKV88-T2TMH-G7BHP,或者另行百度。
新建一个项目请选择windows 窗体应用程序。
设置窗体背景图片,调整窗口为合适大小
设置FromBoderStyle为none(窗体没有边框线)
设置StartPosition为CenterScreen(窗体自动在屏幕正中间启动)
设置showInTaskBar为false(是否显示在任务栏中)
运行界面如下:
根据PSD效果图(图片素材下载)进行控件选择与设置,其中图片控制设置背景色为Transparent
密码文本框中设置PasswordChar为*。
注意控件的名称要具有可读性,建议用tbx表示Textbox,btn表示Button。
在界面上双击按钮后,进入LoginIn.cs界面,即按钮点击事件的窗口。
退出按钮的代码很简单:this.Close();
延伸知识2:退出程序还是退出窗口?
/*当本窗口是主线程窗口,以下三种方法均可以退出程序
*当本窗口不是主窗口时,如果要退出整个程序,应采用第3种方法,将一次性关闭程序上存在的所有线程。
*如果只是想关闭当前窗口而不退出程序,应采用第一种方法
*当本窗口不是主窗口时,采用第2种方法退出程序时,将会再执行关闭主窗体的步骤。
*/
this.Close();
Application.Exit();
Application.ExitThread();
让我们的界面更智能一些,退出前进行确认提示:你确定要退出吗?
这里需要获取到用户点击了哪个按钮,一般情况下,MessageBox的返回值是DialogResult,所以退出按钮的点击事件可以这么写:
//退出按钮的点击事件 private void btnQuit_Click(object sender, EventArgs e) { //简单地弹出消息框 //MessageBox.Show("你确定要退出吗?","退出登陆?",MessageBoxButtons.YesNo,MessageBoxIcon.Question); //对消息框进行判断 if (MessageBox.Show("你确定要退出吗?", "退出登陆?", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { this.Close(); } }
延伸知识:Messagebox的使用
MessageBox.Show()共有21中重载方法。现将其常见用法总结如下:
(1)MessageBox.Show("Hello~~~~");
最简单的,只显示提示信息。
(2)MessageBox.Show("There are something wrong!","ERROR");
可以给消息框加上标题。
(3)if (MessageBox.Show("Delete this user?", "Confirm Message",j.OKCancel) == DialogResult.OK)
{
//delete
}
询问是否删除时会用到这个。
(4)if (MessageBox.Show("Delete this user?", "Confirm Message",MessageBoxButtons.OKCancel,MessageBoxIcon.Question) == DialogResult.OK)
{
//delete
}
可以给MessageBox加上一个Icon,.net提供常见的Icon共选择。
(5)if (MessageBox.Show("Delete this user?", "Confirm Message", MessageBoxButtons.OKCancel,MessageBoxIcon.Question,MessageBoxDefaultButton.Button2) == DialogResult.OK)
{
//delete
}
可以改变MessageBox的默认焦点,如下:
(6)if (MessageBox.Show("Delete this user?", "Confirm Message", MessageBoxButtons.OKCancel,MessageBoxIcon.Question,MessageBoxDefaultButton.Button2,MessageBoxOptions.RtlReading) ==DialogResult.OK)
{
//delete
}
反向显示:
(7)if (MessageBox.Show("Delete this user?", "Confirm Message", MessageBoxButtons.OKCancel,MessageBoxIcon.Question, MessageBoxDefaultButton.Button2, MessageBoxOptions.RightAlign,true) ==DialogResult.OK)
{
//delete
}
添加Help按钮:
(8)if (MessageBox.Show("Delete this user?", "Confirm Message", MessageBoxButtons.OKCancel,MessageBoxIcon.Question, MessageBoxDefaultButton.Button1, MessageBoxOptions.RtlReading,@"/folder/file.htm") == DialogResult.OK)
{
//delete
}
指定帮助文件的路径,点击即可打开该路径下的帮助文件。
(9)//HelpNavigator指定常数来指示要显示的帮助文件元素。Find 帮助文件将打开到搜索页。
if (MessageBox.Show("Delete this user?", "Confirm Message", MessageBoxButtons.OKCancel,MessageBoxIcon.Question, MessageBoxDefaultButton.Button1, MessageBoxOptions.RtlReading,@"/folder/file.htm", HelpNavigator.Find) == DialogResult.OK)
{
//delete
}
知识3:其他的事件设置。
(1)为密码添加鼠标滑过提示语。(提示:添加控件tooltip,在文本框的鼠标经过事件)
private void tbxPwd_MouseEnter(object sender, EventArgs e) { //为密码文本框添加鼠标经过提示 tipPwd.SetToolTip(tbxPwd, "请输入密码"); }
延伸知识3:其他的事件设置。
(2)输入用户名后点击回车后自动进入输入密码
//输入用户后点击回车后进行密码文本框 private void tbxUsername_KeyPress(object sender, KeyPressEventArgs e) { //ASCII码13代表的是回车键 if (e.KeyChar == 13) tbxPwd.Focus(); }
至此,简单的用户交互完成。
现在进入最为重要的登陆按钮功能实现,也就是输入验证与合法身份的验证。
先进行简单的输入验证和逻辑判定。这里的登录判断方法我们用IsValidate自定义方法来验证,可以写在下方。
//登陆按钮的单击事件 private void btnLogin_Click(object sender, EventArgs e) { //进行输入验证 if (tbxUsername.Text == "请输入用户名" || tbxUsername.Text == "") { MessageBox.Show("用户名不能为空!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error); tbxUsername.Focus(); } else if (tbxPwd.Text == "") { MessageBox.Show("密码不能为空!", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error); tbxPwd.Focus(); } else if (IsValidate(tbxUsername.Text.Trim(), tbxPwd.Text.Trim())) { MessageBox.Show("验证通过,欢迎你," + tbxUsername.Text, "登陆成功", MessageBoxButtons.OK, MessageBoxIcon.Information); //跳转到新窗口,待续。。。。 } else { MessageBox.Show("用户密码不匹配,请重新输入!", "登陆失败", MessageBoxButtons.OK, MessageBoxIcon.Error); tbxUsername.Text = String.Empty; tbxPwd.Text = String.Empty; } }
在方法前面加上系统设置的注释行,可以在调用这个方法是得到相应的提示,有助于提高代码的可读性。自定义方法的注释写法可以在该方法被调用时自动弹出提示本方法的作用和参数。
5. 数据库初始连接方式(即用即开)——查询1:验证用户名密码是否匹配
提示:如果还没有建立数据库,先附加数据库Northwind。
SqlDataReader对象——查询1:验证工号密码是否匹配
1) 添加命名空间:using System.Data.SqlClient;
2) 申明数据库连接
3) 打开数据库连接
4) 申明数据库操作语句
5) 申明数据库操作结果集SqlDataReader对象
6) 判定结果集(SqlDataReader. hasrows判断是否有结果)
7) 显式关闭数据库连接
/// <summary> /// 验证用户密码是否匹配,验证通过则返回true /// </summary> /// <param name="strUserName"> 用户名</param> /// <param name="strPwd">密码</param> /// <returns>如果用户密码是匹配的,则返回为真</returns> public bool IsValidate(string strUserName, string strPwd) { //初学者的写法,即开即用的数据库连接 SqlConnection conn = new SqlConnection("Server=LocalHost;Integrated Security = SSPI; Database=Northwind"); conn.Open(); string strSql = "SELECT * FROM Employees WHERE FirstName='" + strUserName + "' AND Password='" + strPwd + "'"; SqlCommand cmd = new SqlCommand(strSql, conn); //SQL结果集返回给reader SqlDataReader reader = cmd.ExecuteReader(); //如果有结果集,说明可以查找到满足条件的记录 if (reader.HasRows) { conn.Close(); return true; } else { conn.Close(); return false; } }
6. 数据库操作方式——查询2:通过用户名获取雇员姓名和职务
SqlDataAdapter +DataSet 对象——查询2:通过用户名返回职员的头衔
1) 添加命名空间:using System.Data.SqlClient;
2) 申明数据库连接
3) 申明数据库操作语句
4) 申明数据库适配器对象 sqlDataAdapter
5) 申明数据集Dataset对象
6) 调用适配器的填充方法数据集Dataset
7) 判定结果集(如果被填充的表格内有数据行,则返回这个表格内列为Title的值)
/// <summary> /// 通过用户名获取职员的头衔 /// </summary> /// <param name="strUsername">用户名</param> /// <returns>职员的头衔,如销售代表、销售经理、副总裁等</returns> public string GetTitleByUserName(string strUsername) { SqlConnection conn = SqlHelper.GetConnection(); string strSql = "SELECT * FROM Employees WHERE FirstName='" + strUsername + "'"; SqlDataAdapter adapter = new SqlDataAdapter(strSql, conn); DataSet ds = new DataSet(); adapter.Fill(ds, "Employees"); if (ds.Tables.Count > 0) { string strResult = ds.Tables[0].Rows[0]["Title"].ToString(); return strResult; } else return null; }
本课为winform初步入门,虽然我们可以实现了与数据库的连接并验证,但是这样的连接时有问题的。
大家可以想象一次,每次数据库连接我们都写出他的数据库连接字符串,然后关闭数据库。(如果你忘记了,那么会报错的)那么每次数据库变更,就意味着我们要修改每个数据库连接字符串,本例中就得修改两次。这样对于变化是很不利的。
第二个问题安全问题,这样的连接方式会导致数据库注入式攻击成功的。
延伸知识——SqlDataReader与SqlDatapter区别与使用场合:
1,SqlDataReader //基于连接,只读访问 适合数据量较小。
SqlDataAdapter //基于非连接,SqlDataAdapter 读取数据后将数据集放入DataSet ,DataSet 的数据存在本地客服机内存。适于数据量较大时,可以另行修改,最后再把修改结果返回给数据库。
2,SqlDataReader返回的是一个数据读写器,只能一条条的读,操作起来不灵活,一般在只读的时候才用到。
SqlDataAdapter返回的是数据集或者表,可以对其中的数据作任意操作
3,写法上有所不同:
SqlDatReader执行前须先打开数据库,然后须生成一个COMMAND对象。再由COMMAND.EXECUTEREADER()方法赋值。完成后须手动关闭联接。
SqlCommand cmd = new SqlCommand("select * from stu", conn);
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
。。。。。
conn.close();
SqlDataAdapter 执行时,自动打开数据库,且不用Command的ExecuteReader方法进行赋值,完成后自动断开联接。
SqlDataAdapter adptr = new SqlDataAdapter(sql, conn);
DataSet ds = new DataSet();
adptr.Fill(ds, "stu");
(1)SQL Server的连接方式
以本地服务器(LocalHost),数据库(Northwind)为例,可以有以下一些连接方式:
SqlConnection conn=new SqlConnection( "Server=LocalHost;Integrated Security = SSPI; Database=Northwind");
说明;Integrated Security默认值是False,此时需要提供Uid和Pwd,即将以Sql Server 用户身份登陆数据库;
如果设置为True,Yes 或 SSPI,表示集成验证,即将以Windows用户身份登陆数据库。这样方式的好处是不需要在连接字符串中编写用户名和密码,从一定程度上说提高了安全性。
在Windows应用程序中是以当前系统帐户登录的。但如果换成是ASP.NET应用程序,则根据其运行宿主环境的不一样,可能会有差异。
1)Windows XP :ASPNET帐号
2.)Windows 2003或者以后的版本:NetWork Service帐号
知道这个原理之后,那么在ASP.NET中使用这种验证方式,需要授予这两个帐号对于数据库的访问权限。
SqlConnection conn = new SqlConnection("Data Source=LocalHost;Integrated Security= SSPI; Initial Catalog=Northwind;");
说明:这两个语句的不同之处在于Server和Database,Data Source和Initial Catalog配对使用的。
SqlConnection conn = new SqlConnection(" Data Source=LocalHost;Initial Catalog=Northwind; Integrated Security=SSPI;Persist Security Info=False;Workstation Id=XURUI;Packet Size=4096; ");
说明:Persist Security Info表示是否保存安全信息,可以简单的理解为"ADO在数据库连接成功后是否保存密码信息",True表示保存,False表示不保存。如果数据库连接成功后不再需要连接的密码,出于安全性考虑,建议将Persist Security Info设为false,以防止后门程序取得数据库连接的密码。
SqlConnection conn = new SqlConnection(" Uid=sa;Pwd=***;Initial Catalog=Northwind;Data Source=LocalHost;Connect Timeout=900");
说明:
" uid=sa ":连接数据库的验证用户名为sa。这里是简写,完整写法是" user id=sa ".
" pwd=":对应sa用户连接数据库的验证密码,他的全称为"pwd",所以我们可以写为" password=***".注意,SQL Server必须已经设置了需要用户名和密码来登录,否则不能用这样的方式来登录.
"initial catalog=Northwind":使用的数据源为"Northwind"这个数据库.他的别名为"Database",本句可以写成"Database=Northwind".
"Server=YourSQLServer":使用名为"YourSQLServer"的服务器.他的别名为"Data Source","Address","Addr".如果使用的是本地数据库且定义了实例名,则可以写为"Server=(local)\实例名";如果是远程服务器,则将"(local)"替换为远程服务器的名称或IP地址.
"Connect Timeout=900":连接超时时间为900秒.
更多字符串连接说明请看MSDN。
2、SQL Server的用户设置
问题一、采用连接字符串
SqlConnection conn = new SqlConnection(" Uid=sa;Pwd=***;Initial Catalog=Northwind;Data Source=LocalHost;Connect Timeout=900");
错误:
用户"sa"登陆失败,没有可信任的Sql Server连接
查资料后找到解决方法:
原因:Sql Server的验证方式需要设置为Sql Server验证和Windows集成验证的混合方式,如果仅设置为后一种方式,就会出像上述问题
解决:运行Sql Server的企业管理器,点击服务器,在右键菜单中选择属性,选安全性,更改验证方式即可
问题二、采用连接字符串
SqlConnection conn = new SqlConnection("Data Source=LocalHost;Integrated Security=SSPI;Initial Catalog=Northwind;");
错误:
用户"computername\IWAM_servername"登陆失败
原因:SQL Server的登陆用户中不包括IWAM_servername
解决方法:运行Sql Server的企业管理器,点击服务器,选安全性,选登陆,新建登陆中加入IWAM_servername,并配备相应的权限,如只能访问Northwind数据库,数据库的角色设置为public和db_owner。
3、关于连接的安全性
最好使用SSPI的集成安全方式连接数据库,而sa用户的方式连接会存在安全隐患,我认为主要是因为在安装SQL Server时,经常会为了访问的方便设置sa的密码为空,黑客一旦让sa成为管理员,就可以获得对系统的所有访问权限。所以为了数据库的安全,可以设置 SQL server的访问用户只能经过windows集成验证,设置sa的安全密码,加强数据库的安全性。当然设置为windows集成验证后,数据库的性能和访问的灵活性势必会受到影响,管理员可以针对每一个数据库设置不同的验证方式,而不必对SQL server设置成统一的方式。
SQL注入式攻击是利用是指利用设计上的漏洞,在目标服务器上运行Sql命令以及进行其他方式的攻击动态生成Sql命令时没有对用户输入的数据进行验证是Sql注入攻击得逞的主要原因。比如: 如果你的查询语句是select * from admin where username='"&user&"' and password='"&pwd&"'" 那么,如果用户名是:1' or '1'='1 那么,你的查询语句将会变成: select * from admin where username='1 or '1'='1' and password='"&pwd&"'" 这样你的查询语句就通过了,从而就可以进入你的管理界面。
由此可见,我们的数据库连接语句是有漏洞的,因此解决办法之一是对用户的输入进行检查。特别是一些特殊字符,比如单引号,双引号,分号,逗号,冒号,连接号等进行转换或者过滤。
解决方法之二:需要使用sqlparameter来规避这类问题。因此我们进入第二课SQLhelper的讲解与使用。