首先我们模拟下简单的登录功能:
简单需求:
模拟用户登录的简单实现
业务描述:
程序运行 的时候,提供一个输入的人口,可以使用输入用户名个密码,校验用户名和密码是否合法,数据库中是否存在用户
合法登录成功,否则注册登录
数据准备:
设计数据库表,通常我们使用建模工具:PowerDesigner
接下来上代码:
db.properties配置文件如下:
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/user user=root password=guisha
实现如下:
package com.guisha.JDBC.Logn;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;
public class JDBCTest {
public static void main(String[] agre) {
//获取登录时的用户和密码
Map<String, String> loginInfo = loginInfo();
//获取用户名登录验证
boolean loginSuccess = login(loginInfo);
//输出结果验证
System.out.println(loginSuccess ? "登录成功!" : "请注册登录!");
}
private static boolean login(Map<String, String> loginInfo) {
//登录标记
boolean flag = false;
//定义用户名和登录密码
String loginName = loginInfo.get("loginName");
String loginPwa = loginInfo.get("loginPwa");
//使用的接口
Connection conn = null;
Statement stan = null;
ResultSet result = null;
try {
InputStream input = JDBCTest.class.getClassLoader().getResourceAsStream("db.properties");
Properties property = new Properties();
try {
//装载配置文件
property.load(input);
String driver = property.getProperty("driver");
String url = property.getProperty("url");
String user = property.getProperty("user");
String password = property.getProperty("password");
//注册驱动
Class.forName(driver);
//从输入字节流中读取属性列表(键和元素对)。输入流采用load(Reader)中指定的简单的面向行的格式,并假定使用ISO 8859-1字符编码。
try {
//创建链接
conn = DriverManager.getConnection(url, user, password);
//获取数据库操作对象
stan = conn.createStatement();
//执行Sql,获取数据
String sql = "select * from loginname where NAME='" + loginName + "' and NAMEPASS= '" + loginPwa + "' ";
// 查询结果集
result = stan.executeQuery(sql);
//判断
if (result.next()){
flag = true;
}
} catch (SQLException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}finally {
//释放资源
if (result != null){
try {
result.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//释放资源
if (stan != null){
try {
stan.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//释放资源
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//返回标识
return flag;
}
public static Map<String, String> loginInfo() {
//接受键盘输入
Scanner scanner = new Scanner(System.in);
//输入用户名
System.out.println("请输入用户名:");
String loginName = scanner.nextLine();
//输入密码
System.out.println("请输入密码:");
String loginPwa = scanner.nextLine();
//创建键值对集合
Map<String, String> map = new HashMap<String, String>();
//将数据添加到map集合对象中
map.put("loginName", loginName);
map.put("loginPwa", loginPwa);
//返回集合对象
return map;
}
}
我们需要了解SQL注入

以上代码中执行执行SQL部分,这里完成了SQL语句的拼接,而executeQuery这里是将sql语句发送给DBMS进行代码编译
正好将用户提供的"非法信息"编译进去,导致原SQL语句的含义被扭曲,会导不正常的操作变的正常、
导致SQL注入的根本原因是什么?
用户输入的信息中包含SQL语句的关键字,并且这些关键字参与sql语句的编译过程,导致SQL语句原意改变,进而达到SQL注入的效果(不能小视,可能会造成数据库崩溃或者被改变)
解决SQL注入问题?
首先我们知道出现SQL注入的原因是用户在提供的信息包含SQL语句的关键字,并且在传给DBMS预编译时传入了非法的SQL信息,那么,只要用户提供的信息不参与SQL语句的编译过程,就可以解决问题(即使信息中包含SQL语句的关键字,但是不参与预编译,不起作用)。
想要用户信息不参与SQL预编译,就需要使用java.sql.PreparedStatement接口,此接口继承了java.sql.Statement。
PreparedStatement是属于预编译的数据库操作对象,原理是:预先对SQL语句的框架进行预编译,然后再给SQL语句传值
我们对代码进行修改:
package com.guisha.JDBC.Logn;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;
public class JDBCTest {
public static void main(String[] agre) {
//获取登录时的用户和密码
Map<String, String> loginInfo = loginInfo();
//获取用户名登录验证
boolean loginSuccess = login(loginInfo);
//输出结果验证
System.out.println(loginSuccess ? "登录成功!" : "请注册登录!");
}
private static boolean login(Map<String, String> loginInfo) {
//登录标记
boolean flag = false;
//定义用户名和登录密码
String loginName = loginInfo.get("loginName");
String loginPwa = loginInfo.get("loginPwa");
//使用的接口
Connection conn = null;
PreparedStatement ps = null;
ResultSet result = null;
try {
InputStream input = JDBCTest.class.getClassLoader().getResourceAsStream("db.properties");
Properties property = new Properties();
try {
//装载配置文件
property.load(input);
String driver = property.getProperty("driver");
String url = property.getProperty("url");
String user = property.getProperty("user");
String password = property.getProperty("password");
//注册驱动
Class.forName(driver);
//从输入字节流中读取属性列表(键和元素对)。输入流采用load(Reader)中指定的简单的面向行的格式,并假定使用ISO 8859-1字符编码。
try {
//创建链接
conn = DriverManager.getConnection(url, user, password);
//获取数据库操作对象
//SQL语句,其中一个 ? ,表示一个占位符,一个?将来接受一个“值”,注意:占位符不能使用 ' ' 括起来
String sql = "select * from loginname where NAME= ? and NAMEPASS = ? ";
ps= conn.prepareStatement(sql);
//给占位符串 “值” (第一个? 下标为1,第二个为2,切记 JDBC中所有的下标从1开始)
ps.setString(1,loginName);
ps.setString(2,loginPwa);
//执行Sql,获取数据对语句进行预编译
// 获取结果集
result = ps.executeQuery();
//判断
if (result.next()){
flag = true;
}
} catch (SQLException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}finally {
//释放资源
if (result != null){
try {
result.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//释放资源
if (ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//释放资源
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//返回标识
return flag;
}
public static Map<String, String> loginInfo() {
//接受键盘输入
Scanner scanner = new Scanner(System.in);
//输入用户名
System.out.println("请输入用户名:");
String loginName = scanner.nextLine();
//输入密码
System.out.println("请输入密码:");
String loginPwa = scanner.nextLine();
//创建键值对集合
Map<String, String> map = new HashMap<String, String>();
//将数据添加到map集合对象中
map.put("loginName", loginName);
map.put("loginPwa", loginPwa);
//返回集合对象
return map;
}
}
