【Unity+MySQL】实现注册登录系统(升级版)

news2024/12/25 16:30:26

目录

  • 1 UI界面重新设计
    • 1.1 注册界面
    • 1.2 登录界面
    • 1.3 交互实现
  • 2 注册功能完善
    • 2.1 判断用户输入的用户名是否与数据库中的重复
    • 2.2 将当前时间更新至用户表的当前注册时间列
    • 2.3 将用户输入的注册密码使用哈希加密
  • 3 登录功能完善

接着 上篇文章所谈到的系统缺陷,这篇文章进行升级解决。

1 UI界面重新设计

问题:注册界面与登录界面是同一个界面,导致用户输入用户密码进行注册后,即可点击登录。

解决:在同一个场景中分别创建注册界面和登录界面,使用SetActive控制注册/登录成功后UI的显示与隐藏。

整体的UI框架搭建如下图所示:
在这里插入图片描述

1.1 注册界面

在这里插入图片描述

其中,底下蓝色的文字作为提示信息提示用户的注册情况。

1.2 登录界面

在这里插入图片描述

其中,底下紫色的文字作为提示信息提示用户的注册情况。

1.3 交互实现

由于这里注册与登录使用的是同一个输入框,因此在登录或注册后对输入框清空。这里还需要注意一点,需要判断登录和注册时用户名密码是否为空,如果为空,给出不能为空的提示。

交互功能代码:

using UnityEngine;
using UnityEngine.UI;
using MySql.Data.MySqlClient;
using System;

public class DatabaseManager : MonoBehaviour
{
    // 数据库连接相关变量
    private MySqlConnection connection;
    private string serverName = "localhost";
    private string dbName = "UnityGame";	// 数据库名
    private string userName = "root";		// 登录数据库的用户名
    private string password = "123456";		// 登录数据库的密码
    private string port = "3306";           // MySQL服务的端口号

    // 注册UI和登录UI
    public GameObject RegisterUI;
    public GameObject LoginUI;

    // 用户名输入框和密码输入框
    public InputField usernameInputField;
    public InputField passwordInputfield;

    // 注册消息和登录消息
    public Text registerMessage;
    public Text loginMessage;

    void Start()
    {
        // 初始化UI状态
        LoginUI.SetActive(true);
        RegisterUI.SetActive(false);

        // 连接数据库
        string connectionString = "Server=" + serverName + ";Database=" + dbName + ";Uid=" + userName
                                  + ";Pwd=" + password + ";Port=" + port + ";";
        connection = new MySqlConnection(connectionString);
        connection.Open();
        Debug.Log("连接数据库成功");
    }

    // 注册逻辑
    public void OnRegister()
    {
        // 从输入框获取用户名和密码
        string username = usernameInputField.text;
        string password = passwordInputfield.text;

        if (username == "" || password == "")
        {
            registerMessage.text = "账号或密码不能为空";
        }

        else
        {
            // 构造插入数据的SQL语句,并将用户名和密码赋值给参数
            string query = "INSERT INTO usersinfo(username, password) VALUES (@username, @password)";
            MySqlCommand cmd = new MySqlCommand(query, connection);
            cmd.Parameters.AddWithValue("@username", username);
            cmd.Parameters.AddWithValue("@password", password);

            // 执行SQL语句,获取影响的行数
            int rowsAffected = cmd.ExecuteNonQuery();

            // 根据影响的行数给出注册成功或失败的消息,并清空输入框
            if (rowsAffected > 0)
            {
                Debug.Log("注册成功");
                registerMessage.text = "注册成功";
            }
            else
            {
                Debug.Log("注册失败");
                registerMessage.text = "注册失败";
            }
            usernameInputField.text = "";
            passwordInputfield.text = "";
        }
    }

    // 登录逻辑
    public void OnLogin()
    {
        // 从输入框获取用户名和密码
        string username = usernameInputField.text;
        string password = passwordInputfield.text;

        if(username == "" || password == "")
        {
            loginMessage.text = "账号或密码不能为空";
        }

        else
        {
            // 构造查询数据的SQL语句,并将用户名和密码赋值给参数
            string query = "SELECT COUNT(*) FROM usersinfo WHERE username=@username AND password=@password";
            MySqlCommand cmd = new MySqlCommand(query, connection);
            cmd.Parameters.AddWithValue("@username", username);
            cmd.Parameters.AddWithValue("@password", password);

            // 执行SQL语句,获取查询结果
            object result = cmd.ExecuteScalar();
            int count = Convert.ToInt32(result);

            // 根据影响的行数给出注册成功或失败的消息,并清空输入框
            if (count > 0)
            {
                Debug.Log("登录成功");
                loginMessage.text = "登录成功";
            }
            else
            {
                Debug.Log("登录失败");
                loginMessage.text = "登录失败";
            }
            usernameInputField.text = "";
            passwordInputfield.text = "";
        }
    }
}

相关变量绑定:
在这里插入图片描述
去注册的按钮事件绑定:
在这里插入图片描述

去登录的按钮事件绑定:
在这里插入图片描述

2 注册功能完善

问题1:用户注册时没有对用户信息进行校验,如一个用户用同一个用户名进行注册时应该进行提示、用户名或密码为空也应该进行提示。
问题2:用户注册时的注册时间没有加入用户表。
问题3:用户注册时输入的密码以明文存储于数据库中,这是不安全的。

2.1 判断用户输入的用户名是否与数据库中的重复

使用SQL查询语句查询数据库中是否存在具有给定用户名的用户记录,检查查询结果并根据需要返回检查用户输入的信息。如果 count 变量的值为0,则表示数据库中不存在具有该用户名的用户记录,可以继续进行注册流程。如果 count 变量的值大于0,则表示该用户名已经被占用,需要提示用户选择不同的用户名。

修改后的注册功能的代码实现:

	// 注册逻辑
    public void OnRegister()
    {
        // 从输入框获取用户名和密码
        string username = usernameInputField.text;
        string password = passwordInputfield.text;

        if (username == "" || password == "")
        {
            registerMessage.text = "账号或密码不能为空";
        }

        else
        {
            // 检查数据库中是否存在具有给定用户名的用户记录
            string query1 = "SELECT COUNT(*) FROM usersinfo WHERE username = @Username";
            MySqlCommand cmd1 = new MySqlCommand(query1, connection);
            cmd1.Parameters.AddWithValue("@Username", username);
            int count = Convert.ToInt32(cmd1.ExecuteScalar());

            // 根据查询结果提示用户
            if (count > 0)
            {
                Debug.Log("用户名已存在,请选择不同的用户名!");
                registerMessage.text = "用户名已存在,请选择不同的用户名!";
            }
            else
            {
                // 构造插入数据的SQL语句,并将用户名和密码赋值给参数
                string query2 = "INSERT INTO usersinfo(username, password) VALUES (@username, @password)";
                MySqlCommand cmd2 = new MySqlCommand(query2, connection);
                cmd2.Parameters.AddWithValue("@username", username);
                cmd2.Parameters.AddWithValue("@password", password);

                // 执行SQL语句,获取影响的行数
                int rowsAffected = cmd2.ExecuteNonQuery();

                // 根据影响的行数给出注册成功或失败的消息
                if (rowsAffected > 0)
                {
                    Debug.Log("注册成功");
                    registerMessage.text = "注册成功";
                }
                else
                {
                    Debug.Log("注册失败");
                    registerMessage.text = "注册失败";
                }
            }
            //清空输入框
            usernameInputField.text = "";
            passwordInputfield.text = "";
        }
    }

2.2 将当前时间更新至用户表的当前注册时间列

将usersinfo的createtime列类型设置为timestamp,并将其默认值修改为CURRENT_TIMESTAMP。
在这里插入图片描述
注册成功后插入数据库的结果:
在这里插入图片描述

2.3 将用户输入的注册密码使用哈希加密

在C#脚本中对用户注册和登录的结果都使用哈希进行加密,这样在进行比较时,都是使用加密后的密文进行比较的。

修改的部分代码:

using System.Security.Cryptography;
    
	// 加密密码
    private static string HashPassword(string password)
    {
        SHA256Managed crypt = new SHA256Managed();
        StringBuilder hash = new StringBuilder();
        byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(password));
        foreach (byte theByte in crypto)
        {
            hash.Append(theByte.ToString("x2"));
        }
        return hash.ToString();
    }

	// 注册逻辑
    public void OnRegister()
    {
        // 从输入框获取用户名和密码
        string username = usernameInputField.text;
        //使用哈希进行加密
        string password = HashPassword(passwordInputfield.text);
        
        //省略
    }

	// 登录逻辑
    public void OnLogin()
    {
        // 从输入框获取用户名和密码
        string username = usernameInputField.text;
        //使用哈希进行加密
        string password = HashPassword(passwordInputfield.text);

        //省略
    }

其中,加入了关闭数据库,用户登录成功后关闭数据库。

注册成功后插入数据库的结果:
在这里插入图片描述

3 登录功能完善

问题:用户登录时,没有针对特定错误进行提示,不论是因用户名密码错误还是该用户未注册都是提示“登录失败”。

修改后的登录功能的代码实现:

	// 登录逻辑
    public void OnLogin()
    {
        // 从输入框获取用户名和密码
        string username = usernameInputField.text;
        //使用哈希进行加密
        string password = HashPassword(passwordInputfield.text);

        if (username == "" || password == "")
        {
            loginMessage.text = "账号或密码不能为空";
        }
        else
        {
            // 构造查询数据的SQL语句,并将用户名和密码赋值给参数
            string query = "SELECT COUNT(*) FROM usersinfo WHERE username=@username AND password=@password";
            MySqlCommand cmd = new MySqlCommand(query, connection);
            cmd.Parameters.AddWithValue("@username", username);
            cmd.Parameters.AddWithValue("@password", password);

            // 执行SQL语句,获取查询结果
            object result = cmd.ExecuteScalar();
            int count = Convert.ToInt32(result);

            // 根据影响的行数给出注册成功或失败的消息,并清空输入框
            if (count > 0)
            {
                Debug.Log("登录成功");
                loginMessage.text = "登录成功";
            }
            else
            {
                // 根据查询结果给出不同的提示消息
                string errorMessage;
                query = "SELECT COUNT(*) FROM usersinfo WHERE username=@username";
                cmd = new MySqlCommand(query, connection);
                cmd.Parameters.AddWithValue("@username", username);
                result = cmd.ExecuteScalar();
                count = Convert.ToInt32(result);
                if (count == 0)
                {
                    errorMessage = "用户名不存在";
                }
                else
                {
                    errorMessage = "密码错误";
                }

                Debug.Log("登录失败:" + errorMessage);
                loginMessage.text = errorMessage;
            }
            usernameInputField.text = "";
            passwordInputfield.text = "";
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/441355.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

==与equals()的理解

java中的数据类型分为基本数据类型、基本数据类型对应的包装类型(引用类型),引用类型三种数据类型。 每一个基本类型java都提供了一个与之对应的包装类型,该包装类型是一个引用类型,并且在基本类型与包装类型之间提供了自动拆箱和…

AD21原理图----网络连线(网络线、网络标签、总线、差分对、信号线束)

目录 网络连线 网络线(Wire) 网络标签 总线 差分对 信号线束 网络连线 网络线(Wire) 网络标签 可以跨原理图 总线 用于放置同一类数据 使用步骤 第一步:先绘制网络线 第二步:利用网络标签进行连接&a…

虚拟机下Ubuntu系统的Docker部署

虚拟机下Ubuntu系统的微服务项目Docker部署 文章目录 虚拟机下Ubuntu系统的微服务项目Docker部署1、Ubuntu安装 Docker2、修改后端微服务的配置2.1 修改 MySQL 的配置2.2 修改 Redis 的配置2.3 修改 Nacos 的配置 3、生成微服务镜像4、拉取远程镜像5、生成前端镜像5.1 准备文件…

MacOS安装MongoDB与Redis

1.安装MongoDB: brew tap mongodb/brew brew install mongodb-community 后台服务方式运行mongodb: brew services restart mongodb/brew/mongodb-community 直接运行mongodb非后台服务 /usr/local/opt/mongodb-community/bin/mongod --config /usr/local/etc/mongod.con…

化工行业数字化“智能工厂”-解决方案(ppt可编辑)

本资料来源公开网络,仅供个人学习,请勿商用,如有侵权请联系删除。 总体架构 设计理念—数据集成与流转 九大核心价值之一 九大核心价值之二 九大核心价值之三 九大核心价值之四 九大核心价值之五 九大核心价值之六 九大核心价值之七 九大核心…

数据库学习-常用的SQL语句

背景: 汇整一下自己学习数据库过程中常见的题目及语句。 一.实例分析题 二.简单SQL查询: 1):统计每个部门员工的数目select dept,count(*) from employee group by dept;2):统计每个部门员工的数目大于一个的记录se…

3.4 迭代法

4.1 雅克比迭代法: 雅可比迭代法是一种用于求解线性方程组的迭代算法,其基本思想是将线性方程组中的系数矩阵拆分为对角线矩阵和非对角线矩阵两部分,并利用对角线矩阵的逆矩阵来迭代求解方程组。 具体地,设线性方程组为Axb&…

操作系统笔记--虚拟内存的使用

1--背景概念 在计算机系统中,当多道程序同时运行时可能会出现内存不足的情况,一般可通过以下技术进行解决: 覆盖技术: 当程序太大超出内存容量时,可以采用手动覆盖的技术,只把需要的指令和数据保存在内存当…

SSM整合、环境配置以及基础综合测试(单表查询、多表查询和数据分页、前后端分离、Vue3)

SSM整合、环境配置以及基础综合测试 准备:创建maven项目以及项目框架准备 SSM整合简介 介绍: SSM(SpringSpringMVCMyBatis) 整合,就是三个框架协同开发。Spring整合Mybatis就是将Mybatis核心配置文件当中数据源的配置、事务处理、以及工厂的配置&…

Docker的使用说明

目录 第一章什么是Docker 1.1.Docker的概述 1.2.什么是容器 1.3.Docker核心概念 第二章.安装 Docker 2.1.安装环境部署 2.2.安装 Docker-CE并设置为开机自动启动 2.2.Docaker的简单信息查看 第三章.Docker 操作 3.1.Docker的镜像操作 3.2.Docker 容器操作 3.3.容器…

Baumer工业相机堡盟工业相机如何联合BGAPISDK和佳能EF变焦镜头实现相机的自动变焦(C#)

Baumer工业相机堡盟工业相机如何联合BGAPISDK和佳能EF变焦镜头实现相机的自动变焦(C#) Baumer工业相机Baumer工业相机BGAPISDK中控制变焦镜头的技术背景代码案例分享第一步:开启相机自动调焦功能模块第二步:控制自动变焦镜头电机的…

Delphi DataSnap 流程分析(二)

Delphi DataSnap 流程分析(一)_看那山瞧那水的博客-CSDN博客 粗略分析了 创建传统DataSnap的流程,现在再分析下创建现在更常用的 方式: DataSnap REST Application 这种方式只支持HTTP(普通HTTP和REST HTTP)通信,不支持TCP通信。 这种方式…

详解C语言string.h中常见的13个库函数(上)

我计划讲解C语言string.h这个头文件中,最常见的13个库函数。为了让大家更加深入的理解这些函数,部分函数我会模拟实现。篇幅所限,如果文章太长了,可能会较难坚持读完,所以我会分几篇博客来讲述。本篇博客主要讲解的函数…

什么是全民开发?|概念、技能和优势

注:全民开发的英文是Citizen Development,由咨询公司Gartner在2010年提出的概念,指非专业开发人员使用低代码或无代码平台创建应用程序,无需IT部门的支持,旨在提高生产力并降低开发成本。 国内普遍将Citizen Developme…

【ROS】单目摄像机的标定

在上节: ROS 教程之 vision : 用笔记本摄像头获取图像 能够使用相机后&#xff0c;就需要对相机进行标定&#xff0c;在ROS上使用原始图像校准单目相机。 操作步骤 1、首先将catkin_ws/src/usb_cam/launch/usb_cam-test.launch的文件内容修改掉。 原有内容&#xff1a; <…

docker 使用Dockerfile 部署springboot项目

1、先准备好你的springboot项目jar包。拉取 openjdk docker pull openjdk:8-jdk-alpine 2、上传你的springboot项目&#xff0c;然后配置 Dockerfile&#xff1a; FROM openjdk:8-jdk-alpine ADD ./springbootstudy.jar.jar /app.jar ENTRYPOINT ["java","-jar…

【源码】Spring Cloud Gateway 是在哪里匹配路由的?

我们知道&#xff0c;经过网关的业务请求会被路由到后端真实的业务服务上去&#xff0c;假如我们使用的是Spring Cloud Gateway&#xff0c;那么你知道Spring Cloud Gateway是在哪一步去匹配路由的吗&#xff1f; 源码之下无秘密&#xff0c;让我们一起从源码中寻找答案。 入…

Ant Design 常见用法与坑点总结(二):Form 表单下拉框设置初始值

前言 Ant Design 是蚂蚁出品的出色优秀的 React 组件库&#xff0c;相信使用 React 进行管理系统开发的小伙伴们或多或少都接触过 Ant Design。很多公司基于 React 开发的管理端系统也都是使用 Ant Design 的组件库。 因此&#xff0c;了解 Ant Design 的常见用法与坑点还是有…

react中如何系统化的处理时间操作?

在 Web 开发中&#xff0c;我们经常需要处理日期和时间的格式化。 在 React 中&#xff0c;这个过程变得更加容易和直观&#xff0c;因为我们可以使用一个叫做 moment 的 npm 包来帮助我们完成这个任务。 什么是 Moment? Moment.js是一个JavaScript库&#xff0c;用于处理日…

使用FFMPEG库将PCM编码为AAC

准备 ffmpeg 版本4.4 准备一段48000Hz 2 channel f32le 格式的PCM原始数据 这里我们直接使用ffmpeg命令行提取 ffmpeg -i beautlWorld.mp4 -ar 48000 -ac 2 -f f32le 48000_2_f32le.pcm -ac 采样率 -ac 音频通道 -f f32le 音频样本数据存储格式&#xff08;f32 ---- float…