使用JDBC连接MySQL数据库-典型案例分析(5)-用户名密码验证功能

使用JDBC连接MySQL数据库--典型案例分析(五)----用户名密码验证功能

前几次有网友转载我的博客也声称原创,我实在对这种人很无语耶,我转载其他人的博客从来都是很尊重的,该是转载的就写明了转载,虽然这里没有人去要求,但是这是对只是的一种尊重,对他人的尊重。人与人之间应如此,哪怕情侣之间也是如此(虽然我没有谈恋爱),但是在生活中我看到无论是小情侣还是小两口,总存在我觉得不尊重对方的地方,这样并不好。

言归正传,这节谢谢如何进行用户名的验证功能。

转载请注明:http://blog.****.net/uniquewonderq

问题:

现去数据库建个表,建好之后,结构如下图:

使用JDBC连接MySQL数据库-典型案例分析(5)-用户名密码验证功能

,本案例的详细要求如下;

1.使用Statement实现用户名和密码的验证功能,并测试用户名为“wonderq”,密码为"root"以及用户名为"chenxin",密码为“a' OR 'b'='b”是否能登录成功。

2.使用PreparedStatement实现用户和密码的验证功能,并测试用户名为"chenxin",密码为“a' OR 'b'='b”是否能登录成功。

方案: 

实现本案例的方案如下:

1.使用Statement实现用户名和密码的验证功能。实例代码如下:

sql="select * from users where username=' "+username+" ' " and password=' "+password+" ' ";
	System.out.println(sql);
	con=ConnectionSource.getConnection();
	stmt=con.createStatement();
	rs=stmr.executeQuery(sql);

上述代码存在SQL注入的问题,可以使用PreparedStatement来解决SQL注入的问题。

   2.使用PreparedStatement实现用户名和密码的验证功能。preparedStatement是Statement的子类,表示预编译的SQL语句的对象。在使用PreparedStatement对象执行SQL命令时,命令被数据库编译和解析,并放入命令缓冲区。缓冲区中的预编译SQL命令可以重复使用。实例代码如下所示:

sql="select * from users where username=? and password=?";
	con=ConnectionSource.getConnection();
	stmt=con.PrepareStatement(sql);
	stmt=setString(1,username);
	stmt=setString(2,password);
	rs=stmt.executeQuery();

   使用PreparedStatement来执行SQL语句。在SQL语句中有2个问号,在代码中要给它们设置值,从左到右,对应,1,2,....而且setxxx的xxx类型与变量类型要一致。

3.关于SQL注入。对于JDBC而言,SQL注入攻击只对Statement有效,对PreparedStatement是无效的,这是因为PreparedStatement不允许在插入时改变查询的逻辑结构。如果有一条SQL语句为:

"select * from 表 where 用户名='用户名'  "

Statement的SQL语句是这样写的:

"select * from 表 where 用户名=' "+变量值+" ' "

而PreparedStatement的SQL语句是这样写的:

"select * from 表 where 用户名=?"

这样输入"aa 'or '1'='1' ",使用Statement执行的SQL语句为:

"select * from 表 where 用户名=' aa 'or '1'='1' "

而使用PreparedStatement是将"' aa 'or '1'='1' "作为一个字符串复制给问号“?”,使其作为"用户名"字段的对应值,这样在防止SQL注入。

步骤:

实现本案例需要如下步骤:

步骤一:创建users表,并插入实例数据

在Mysql数据库中,创建users表,并插入如下实例数据,SQL语句如下所示:

CREATE TABLE users(
id NUMERIC(4),
username VARCHAR(30),
password VARCHAR(30)
);
INSERT INTO users(id,username,password) VALUES (1,'wonderq','root');
INSERT INTO users(id,username,password) VALUES (2,'chenxin','sweet');

使用JDBC连接MySQL数据库-典型案例分析(5)-用户名密码验证功能

步骤二:使用Statement实现验证用户名密码是否存在

新建UserDAO类,在该类中添加login方法,在该方法中使用Statement实现验证用户名密码是否存在的方法,代码如下所示:

<pre name="code" class="java">package dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class UserDAO {
		
	public static void main(String[] args){
		UserDAO dao=new UserDAO();
		dao.login("wonderq", "root");
	}
	public void login(String username,String password){
		Connection con=null;
		Statement stmt=null;
		ResultSet rs=null;
		String sql=null;
		try {
			sql="select * from users where username='"+username+"'"+"and password="+"'"+password+"'";
			System.out.println("执行的sql语句:"+sql);
			con=ConnectionSource.getConnection();
			stmt=con.createStatement();
			rs=stmt.executeQuery(sql);
			if(rs.next()){
				System.out.println("登录成功!");
			}else{
				System.out.println("登录失败!");
			}
		} catch (SQLException e) {
			System.out.println("数据库访问异常!");
			throw new RuntimeException(e);
		}
		finally{
			try {
				if(rs!=null){
					rs.close();
				}
				if(stmt!=null){
					stmt.close();
				}
				if(con!=null){
					con.close();
				}
			} catch (SQLException e2) {
				System.out.println("释放资源发生异常!");
			}
		}
	}
}




步骤三:使用用户名为“wonderq”,密码为"root"测试是否能登录

只用在usersDAO类的主方法加入如下语句:

UserDAO dao=new UserDAO();
		dao.login("wonderq", "root");
运行usersDAO类,控制台输出结果如下:

使用JDBC连接MySQL数据库-典型案例分析(5)-用户名密码验证功能

从输入结果可以看出,使用用户名为“wonderq”,密码为“root”可以登录成功,由于用户名为"wonderq",密码为"root"在数据库中是存在的数据,登陆成功符合预期结果。另外,从输出sql语句来看,最终变量信息替换为实际传入的参数信息了。

步骤四:测试login方法

在UserDAO的main方法中,使用用户名为"chenxin",密码为"a' OR 'b'='b"作为login方法的参数,测试是否能成功登录,代码如下所示:

UserDAO dao=new UserDAO();
		//dao.login("wonderq", "root");
		dao.login("chenxin", "a' OR 'b'='b");
运行UserDAO类,控制台输出如下结果:

使用JDBC连接MySQL数据库-典型案例分析(5)-用户名密码验证功能


从输出结果来看,使用用户名为“chenxin”,密码为"a' OR 'b'='b"可以登录成功,但是用户名为"chenxin",密码为"a' OR 'b'='b"在数据库中是不存在的数据,登录成功不符合预期结果,问题出在哪里呢?

问题出在sql语句上。查看上述控制台输出结果,可以看出SQL语句的where字句中,使用or关键字连接两个表达式,即or关键字后边的表达式如果返回true。而or关键字后面的表达式为" 'b'='b" ,该表达式的返回结果永远为true,因此,where条件的返回结果一定为true。这种现象在编程中成为SQL注入,是应该避免的编程方式。可以使用PreparedStatement来防止SQL注入。

步骤五:使用PreparedStatement实现验证用户名和密码功能

在UserDAO类中更改login方法,在该方法中使用PreparedStatement执行SQL语句,来实现验证用户名密码功能。代码如下所示:

package dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class UserDAO {
		
	public static void main(String[] args){
		UserDAO dao=new UserDAO();
		//dao.login("wonderq", "root");
		dao.login("chenxin", "a' OR 'b'='b");
	}
	public void login(String username,String password){
		Connection con=null;
		PreparedStatement stmt=null;
		ResultSet rs=null;
		String sql=null;
		try {
			sql="select * from users where username= ? and password= ?";
			System.out.println("执行的sql语句:"+sql);
			con=ConnectionSource.getConnection();
			stmt=con.prepareStatement(sql);
			stmt.setString(1, username);
			stmt.setString(2, password);
			rs=stmt.executeQuery();
			if(rs.next()){
				System.out.println("登录成功!");
			}else{
				System.out.println("登录失败!");
			}
		} catch (SQLException e) {
			System.out.println("数据库访问异常!");
			throw new RuntimeException(e);
		}
		finally{
			try {
				if(rs!=null){
					rs.close();
				}
				if(stmt!=null){
					stmt.close();
				}
				if(con!=null){
					con.close();
				}
			} catch (SQLException e2) {
				System.out.println("释放资源发生异常!");
			}
		}
	}
}

步骤六:测试login方法

在UserDAO类的main方法中,使用用户名为"chenxin",密码为"a' OR 'b'='b"作为login方法的参数,测试是否能成功登录,代码就是上面的,运行之后,控制台输出结果:

使用JDBC连接MySQL数据库-典型案例分析(5)-用户名密码验证功能


从输出结果来看,登陆失败。用户名为"chenxin",密码为"a' OR 'b'='b"的数据在数据库users表中是不存在的数据,登录失败符合测试的预期,有效的防止了SQL注入的问题。

本节结束~。。下次进入JDBC的高级编程。。