数据库实践——模拟用户登录功能的实现

数据库实践——模拟用户登录功能的实现

假设用户数据库如下:
在这里插入图片描述
代码实现:

import javax.swing.plaf.nimbus.State;
        import java.sql.*;
        import java.util.HashMap;
        import java.util.Map;
        import java.util.ResourceBundle;
        import java.util.Scanner;

public class UserLogin {
    public static void main(String[] args) {
        //初始化一个用户登录界面
        Map<String,String> userinfo=iniUI();
        //验证登录名和登录密码
        boolean loginSucess=login(userinfo);
        System.out.println((loginSucess? "登录成功!":"登录失败!"));
    }

    /**
     * 用户登录
     * @param userinfo 用户登录信息
     * @return true表示登录成功,false表示登录失败
     */
    private static boolean login(Map<String, String> userinfo) {
        //使用资源绑定器绑定资源配置文件
        ResourceBundle bundle=ResourceBundle.getBundle("jdbc");
        String driver=bundle.getString("driver");
        String url=bundle.getString("url");
        String user=bundle.getString("user");
        String password=bundle.getString("password");

        //JDBC编程
        Connection cnn=null;
        Statement stmt=null;
        ResultSet res=null;

        //登录成功标记
        boolean logSucess=false;

        try {
            //第一步:注册驱动(在配置文件里面直接读取)
            Class.forName(driver);
            //第二步:获取连接
            cnn=DriverManager.getConnection(url,user,password);
            //第三步:获取数据库操作对象
            stmt=cnn.createStatement();
            //第四步:执行sql语句
            //单独定义变量名
            String loginName=userinfo.get("loginName");
            String loginPwd=userinfo.get("loginPwd");

            String sql="select * from t_user where logname='"+loginName+"'and logpwd='"+loginPwd+"'";


             //注意:以下这个是不对的,因为sql是一个字符串,整个selcet语句是一个字符串,,需要将这表达这个意思的真个句子拼接起来
             //String sql="select * from t_user where logname='loginName'and logpwd='loginPwd'";
             //断开理解:
             //String sql="select * from t_user where logname=' "   +loginName+  " 'and logpwd=' "+loginPwd+   "'";
            
            res=stmt.executeQuery(sql);
            //第五步:处理查询结果集
            //z合理不用while,因为不用循环,每次只能查一个用户
            if(res.next()){//如果有数据,表示登陆成功
                logSucess=true;
                return  logSucess;
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //第六步:关闭资源
            if (res != null) {
                try {
                    res.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (stmt!= null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (cnn != null) {
                try {
                    cnn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return logSucess;
    }

    /**
     * 用户登录界面
     * @return返回用户的登录信息
     */
    private static Map<String, String> iniUI() {
        Scanner s=new Scanner(System.in);
        System.out.print("登录名:");
        String loginName=s.nextLine();//读取一行
        System.out.print("登录密码:");
        String loginPwd=s.nextLine();

        //将登录名和登录密码以键值对的方式存入map集合
        Map<String ,String> userloginfo=new HashMap<>();
        userloginfo.put("loginName",loginName);
        userloginfo.put("loginPwd",loginPwd);

        return userloginfo;
    }
}

以上代码实现了:当输入的用户信息和数据库中的内容一致时,可以成功登陆。
但是以上代码存在以下bug (sql注入问题) :存在安全隐患
在这里插入图片描述
**分析发生sql注入的根本原因: 用户输入的信息中含有SQL语句的关键字,并且这些关键字参与SQL语句的编译,导致SQL语句的原意被扭曲,进而达到SQL注入。

**改进: 只要用户提供的信息不参与SQL语句的编译(采用java.sql.PreparedStatement预先对SQL语句的框架进行编译,然后再给SQL语句传“值”),即使用户提供的信息含有SQL的关键字,也不起作用。

代码改进:

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;

public class UserLogin2 {
    public static void main(String[] args) {
        //初始化一个登陆界面
        Map<String,String> userinfo=iniUI();
        //验证信息
        Boolean logsucess=logSucess(userinfo);
        System.out.println(logsucess? "登录成功!":"登录失败!");
    }

    private static Boolean logSucess(Map<String, String> userinfo) {
        //使用资源绑定器绑定资源配置文件
        ResourceBundle bundle=ResourceBundle.getBundle("jdbc");
        String driver=bundle.getString("driver");
        String url=bundle.getString("url");
        String user=bundle.getString("user");
        String password=bundle.getString("password");

        //JDBC编程六步
        Connection cnn=null;
        PreparedStatement stmt=null;
        ResultSet res=null;
        boolean logsucess=false;

        String logName=userinfo.get("logName");
        String logPwd=userinfo.get("logPwd");
        try {
            //第一步:注册驱动
            Class.forName(driver);
            //第二步:获取连接
            cnn= DriverManager.getConnection(url,user,password);
            //第三步:获取预编译的数据库操作对象
            //SQL语句,一个?代表一个占位符,一个?将来接受一个值,但是?不能用单引号扩起来
            String sql="select * from t_user where logname= ? and logpwd= ? ";
            //查询执行到此处,会把SQL语句发送给DBMS,DBMS预编译SQL 语句
            stmt=cnn.prepareStatement(sql);
            //给占位符?传值(预编译之后传值,即用户输入的信息不参与编译,会解决SQL注入问题),
            // 第一个?下标是1,第二个问好下标是2.JDBC的下标是从1开始的
            stmt.setString(1,logName);
            stmt.setString(2,logPwd);
            //第四步:执行SQL语句
            res=stmt.executeQuery();
            //第五步:处理 查询结果集
            if(res.next()){//有数据
                logsucess=true;
                return  logsucess;
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //第六步:释放资源
            if (res != null) {
                try {
                    res.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (cnn != null) {
                try {
                    cnn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
    }
        return logsucess;
    }


    /**
     * 初始化一个登陆界面
     * @return返回用户的登录信息
     */
    private static Map<String, String> iniUI() {

        Map<String,String> userinfo=new HashMap<>();
        Scanner s=new Scanner(System.in);
        System.out.print("登录名:");
        String  loginName=s.nextLine();
        System.out.print("登录密码:");
        String loginPwd=s.nextLine();

        userinfo.put("logName",loginName);
        userinfo.put("logPwd",loginPwd);
        return userinfo;
    }
}

对于Statement和PreparedStatement还需要了解的,可以在查看:Statement和PreparedStatement的对比

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值