zoukankan      html  css  js  c++  java
  • Java 程序设计——登录系统

    重复型服务器

    博客展示的登录系统的服务器端,将实现重复型服务器。

    Client–server model

    客户端-服务器模型(Client–server model)简称C/S结构,是一种网络架构。大部分网络应用程序在编写时都假设一端是客户,另一端是服务器,其目的是为了让服务器为客户提供一些特定的服务。可以将这种服务分为两种类型:重复型或并发型。本博客实现的重复型服务器通过以下步骤进行交互:

    1. 等待一个客户请求的到来。
    2. 处理客户请求。
    3. 发送响应给发送请求的客户。
    4. 返回第 1 步。

    Request/Response model

    请求/响应(Request/Response)模型一种通用的网络模型架构,该模型下永远都由客户端发起请求,由服务器进行响应并发送回响应报文。如果没有客户端进行请求或曾经请求过,那么服务器是无法将消息推送到客户端的。

    三层架构

    本系统将基于三层架构实现,由表示层、逻辑层和存储层 3 层组成。表示层是应用的最高层,负责与用户进行交互,并将通信信息发送给逻辑层。逻辑层执行细节处理来控制应用的功能,连接到存储层。存储层则往往是数据库,用于检索并维护数据。

    表示层向逻辑层发送请求,逻辑层对存储层完成检索和更新数据等操作,最后逻辑层根据存储层的数据对表示层进行响应。从概念上看,三层架构是一种线性关系

    登录系统设计

    登录系统由客户端和服务器 2 个部分组成。

    客户端

    客户端需要接收用户输入的用户名和密码,然后将这 2 个信息发送给服务器。发送完毕之后等待服务器的响应信息,若在一定的时间内收到了服务器的响应,并且响应“操作成功”,则完成用户的登录操作。除了支持用户的登录操作,客户端还应该支持其他基于用户的操作,例如注册用户、密码修改和注销用户等。

    • 修改密码和注销用户的操作,不能在登录前被调用,只能在登录之后。

    服务器

    无论客户端是否启动,服务器应当保持启动的状态,并且持续监听分配给服务器的端口。当服务器收到客户端发送的数据时,服务器对数据进行处理并执行对应的操作。根据服务器的执行情况,若操作成功则向客户端通告操作成功,否则通告失败,接着继续 监听客户端发送的数据。

    数据库连接

    用户名和密码信息将保存在数据库中,当服务器接收到客户端的数据时,将按照客户端请求的操作与数据库进行交互。根据客户端请求的方式不同,服务器与数据库交互时需要执行的操作为:

    用户请求 数据库操作
    注册 INSERT INTO
    登录 SELECT
    密码修改 UPDATE
    用户注销 DELETE

    客户端实现

    UserBehaviorDAO 接口

    由于客户端和服务器的交互方式不仅仅只有三层架构的实现方式,还可以实现多层架构等其他方式。此时服务器及其它层的动作对于客户端来说是不可见的,因此定义 UserBehaviorDAO 接口支持客户端和服务器的交互方式的更换。

    /**
    * UserBehaviorDAO 接口指定了针对用户的行为
    * @author 乌漆WhiteMoon 
    * @version 1.0
    */
    public interface UserBehaviorDAO {
    	
    	/**
    	   * 这个方法将实现用户的注册操作
    	   * @param username 用户名,String
    	   * @param password 密码,String
    	   * @return 操作是否成功,boolean
    	   */
    	  public static boolean registerUser(String username, String password) {
    		return false;
    	  }
    	
    	/**
    	   * 这个方法将实现用户的改密码操作
    	   * @param username 用户名,String
    	   * @param password 密码,String
    	   * @param new_password 新密码,String
    	   * @return 操作是否成功,boolean
    	   */
              public static boolean changePassword(String username, String password, String new_password) {
    		return false;
    	  }
        
           /**
    	   * 这个方法将实现用户的登录操作
    	   * @param username 用户名,String
    	   * @param password 密码,String
    	   * @return 操作是否成功,boolean
    	   */
              public static boolean signIn(String username, String password) {
    		return false;
    	  }
        
            /**
    	   * 这个方法将实现用户的销户操作
    	   * @param username 用户名,String
    	   * @param password 密码,String
    	   * @return 操作是否成功,boolean
    	   */
              public static boolean cancelUser(String username,String password) {
    		return false;
    	  }
    }
    

    UserBehavior 类

    UserBehavior 类是静态类,实现了 UserBehaviorDAO 接口,该类的 4 个方法将把数据传输给套接字进行和服务器的通信。

    服务器实现

    SqlActionDao 类

    由于服务器需要与数据库进行交互,而数据库应该作为一个可替换组件存在,因此定义 SqlActionDao 接口指定了与数据库的交互行为。

    /**
    * SqlActionDao 接口指定了与数据库的交互行为
    * @author 乌漆WhiteMoon 
    * @version 1.0
    */
    public interface SqlActionDao {
    	
    	/**
    	   * 查找用户名是否已存在,用户注册时用
    	   * @param username 被查找的用户名
    	   * @return true为用户名不存在,false为用户名已存在
    	 * @throws SQLException 数据库异常
    	   */
    	public static boolean selectUsername(String username) throws SQLException{
    		return false;
    	}
    	
    	/**
    	   * 核对用户名和密码是否存在且匹配,用户登录和其他增删改操作时使用
    	   * @param username 用户名
    	   * @param password 密码
    	   * @return true为用户名和密码存在且匹配,false为用户名或密码错误
    	 * @throws SQLException 数据库异常
    	   */
    	public static boolean checkUser(String username, String password) throws SQLException{
    		return false;
    	}
    	
    	/**
    	   * 向数据库插入一个uesr记录,注册操作时用,调用该方法前应使用selectUsername()方法检查
    	   * @param username 用户名
    	   * @param password 密码
    	   * @return true为记录插入成功,false为插入失败
    	 * @throws SQLException 数据库异常
    	   */
    	public static boolean insertUser(String username, String password) throws SQLException{
    		return false;
    	}
    	
    	/**
    	   * 删除一条记录,注销用户时用,调用该方法前应使用checkUser()方法检查
    	   * @param username 用户名
    	   * @return true为删除成功,false删除失败
    	 * @throws SQLException 数据库异常
    	   */
    	public static boolean deleteUser(String username) throws SQLException{
    		return false;
    	}
    	
    	/**
    	   * 更新一个uesr的password字段,改密码操作时用,调用该方法前应使用checkUser()方法检查
    	   * @param username 用户名
    	   * @param new_password 新密码,用于替换原有的条目
    	   * @return true为更换成功,false更换失败
    	 * @throws SQLException 数据库异常
    	   */
    	public static boolean updateUserPasswd(String username, String new_password) throws SQLException{
    		return false;
    	}
    }
    

    MySqlAction 类

    MySqlAction 类是静态类,实现了 SqlActionDao 接口,该类将连接到 MySQL 数据库进行对数据的操作。为了支持对数据库的连接,还需要 MysqlConnect 类完成连接操作。

    数据封装

    操作码和分隔符

    客户端发送的有效载荷为一个字符串,该字符串由操作码、用户名和密码 3 个部分组成,3 个部分之间用 “+” 连接。

    服务器接收到数据之后,将数据按照分隔符 “+” 进行分割。

    //分割明文,执行对应的操作
    String result_set[] = result_decode.split("+");
    

    通过操作码执行对应的操作,操作码和用户的请求的关系如下:

    用户请求 数据库操作
    1 注册
    2 登录
    3 密码修改
    4 用户注销
    • 改密码操作还需要传输新密码,因此“密码”部分的内容为 “password '+' newpassword”。

    数据加密

    MD5Util 类

    MD5Util 类只有 getMD5Str() 方法,用于对传入的字符串进行 MD5 加密。MD5Util 类会被 UserBehavior 类调用,传输的用户名和密码都会进行 MD5 加密,从而保证这 2 者的安全性。

    例如对用户名“张三”和密码“123456”调用 getMD5Str() 方法进行加密,输出结果为:

    615db57aa314529aaa0fbe95b3e95bd3
    e10adc3949ba59abbe56e057f20f883e
    

    服务器的日志文件如下所示:

    Base 64 加密

    即使对用户名和密码进行加密,攻击者仍然可能截取密文进行提交,为了保证安全性需要对整个有效载荷进行加密。UserClient 类的 sendRequest 方法使用 base64 加密,加密的代码为:

    //明文写入操作码,跟着用户名即密码
    String Plaintext = actionCode + " " + username + " " + password;
    //对明文进行 base64加密
    String ciphertext = Base64.getEncoder().encodeToString(Plaintext.getBytes("utf-8"));
    

    Base 64 解密

    服务器接收到数据之后要先对数据进行 Base 64 解密,解密的代码如下:

    DataInputStream in = new DataInputStream(server.getInputStream());
    //将客户端传来的密文转成明文
    String result_decode = new String(Base64.getDecoder().decode(in.readUTF()));
    

    MySQL 数据库

    users 表

    数据库中的 users 表用于存储 MD5 加密后的用户名和密码,users 表的字段有。

    下图是存储了 3 个用户信息的 users 表。

    SQL 查询语句

    selectUsername() 方法

    这个方法将基于select查找用户名是否已存在,用户注册时用。

    SELECT username FROM users WHERE binary username = '%s';
    

    checkUser() 方法

    这个方法将基于 select 核对用户名和密码是否存在且匹配,用户登录和其他增删改操作时使用.

    SELECT username,password FROM users WHERE binary username = '%s' AND password = '%s';
    

    insertUser() 方法

    这个方法将基于 insert 向数据库插入一个 uesr 记录,注册操作时用,调用该方法前应使用
    selectUsername() 方法检查。

    INSERT INTO users(username, password) values('%s','%s');
    

    deleteUser() 方法

    这个方法将基于 delete 删除一条记录,注销用户时用,调用该方法前应使用 checkUser() 方法检查。

    "DELETE FROM users WHERE username = '%s';"
    

    updateUserPasswd() 方法

    这个方法将基于 update 向更新一个 uesr 的 password 字段,改密码操作时用,调用该方法前应使用 checkUser() 方法检查。

    UPDATE users SET password='%s' WHERE username = '%s';
    

    Socket 实现

    Socket

    不同端系统的进程是通过彼此之间向套接字发送报文来实现通信,套接字就好比是门禁,想要和应用程序进行通信需要先通过门禁的验证。同理也不是什么报文都能随意出门的,必须是得到允许的报文才会被送出门去。
    为了连接主机,我们需要目标主机的 IP 地址,这样才能知道要发给哪个端系统,就像送信就一定要有收件人。但是由于一台主机上可能运行着好多个进程,需要指定一个端口号,令指定的进程接收分组。需要强调的是,我们自己写的端口需要避开 RFC 定义的协议,例如 HTTP 协议的端口号 80。

    Client-Socket

    UserClient 类

    UserClient 类是基于请求响应模型的客户端套接字,该类应该在客户端被调用,只有 sendRequest() 发送报文一个方法。

    Server-Socket

    Response 类

    本类的方法将接受套接字收到的数据,调用 SqlActionDao 接口执行对客户端请求的操作,操作完成后进行响应。

    UserServer 类

    UserServer 类将继承 Thread 类,run() 方法将保持对分配给该进程的端口的监听,若接收到数据则调用 Response 类中的方法进行操作。

    Customer 类

    用户登录之后,将会把登录的用户信息实例化一个 Customer 类。注意 Customer 类不会保存用户的密码,安全的做法是让用户执行改密码和注销操作时都额外提供一次密码。

    public class Customer {
    	private final String username;
    	private final String username_md5;
    	private LinkedList<Emails> Inbox;    //收件箱
    	private LinkedList<Emails> Outbox;    //发件箱
    	
    	/**
    	   * 这个方法是customer对象的构造器
    	   * @param username 用户名,String
    	   * @return customer对象
    	   */
    	public Customer(String username) {
    		this.username = username;
    		this.username_md5 = MD5Util.getMD5Str(username);
    	}
    }
    

    GUI 设计

    登录界面


    注册用户界面


    密码修改界面

    销户界面

    参考资料

    《计算机网络(第七版)》 谢希仁 著,电子工业出版社
    《TCP/IP 详解 卷1:协议》[美]W.Richard Stevens 著,范建华 胥光辉 张涛 等译,谢希仁 校,机械工业出版社
    《SQL注入攻击与防御(第2版)》 [美]Justin Clarke 著,施宏斌 叶愫 译,清华大学出版社
    计算机网络:协议栈分层
    应用层:HTTP 协议
    HTTP请求/响应模型
    Java DAO 模式
    应用层:UDP 套接字编程
    应用层:TCP 套接字编程
    MySQL——SELECT
    MySQL——增、删、改

  • 相关阅读:
    Hadoop压缩
    Hive数据倾斜总结
    DQL、DML、DDL、DCL
    HashMap/HashSet,hashCode,哈希表
    HashMap详解
    Hive分区和桶
    String不可变StringBuffer可变
    Java线程和守护进程
    Ambari安装小记
    P3
  • 原文地址:https://www.cnblogs.com/linfangnan/p/14100443.html
Copyright © 2011-2022 走看看