本文字数:约2000字,预计阅读时间10-20分钟。

前言相信大部分小伙伴在初次接触到Web项目的时候都是从注册登录开始的。

登录注册是互联网项目中非常常见的一个功能,尤其是在网络社交愈发普及的今天,登录注册功能已是必不可少。

登录注册功能的核心功能其实并不复杂,但对于用户账户的安全性要求往往非常高,导致有些尚未工作的大学生甚至工作了几年的程序员对于登录注册的流程不熟悉。

本文以Web网站开发过程中实现的用户登录注册功能为例,探讨一下登录注册功能实现的过程中遇到的问题以及对应的解决方案。

1.为什么要登录注册登录注册是互联网应用中非常常见的功能,在讨论为什么之前,我想先说一下它的作用:

可以认证用户身份。通过注册登录,应用可以确保用户是合法用户。

例如在即时IM通讯应用中,用户可以通过不同的账号来分辨不同的使用者、从而给对应的人发送对应的消息。保护用户隐私。可以防止其他用户获取到用户的个人信息。

例如在同一电脑上,不同账号的数据信息不会混淆在一起。提供个性化服务。应用可以获取用户的个人信息,为用户提供更加个性化的服务。

通过以上几点,我觉得我们能够较为清晰的认识到了登录注册的功能,所以以上也可以说是“为什么要登录注册”问题的回答。2.登录注册的简单实现最简单的登录注册功能就是:用户输入帐号密码,然后点击登录或者注册,然后处理对应的逻辑,返回给用户成功或者失败。

登录注册的简单流程图以下是建表语句示例:

代码语言:sql复制CREATE TABLE user (

id INT PRIMARY KEY AUTO_INCREMENT,

username VARCHAR(255),

password VARCHAR(255)

);登录界面可以是这样:

登录页面『1』小提示:『1』表示为来源于网络,在文末贴有链接。下文同。

处理流程此处忽略......

应该大部分的初学者都是从这一阶段过来的吧...,但是在实际项目当中,仅仅只定义账号密码是肯定不行的。

3.高手版的登录注册我们可以想到:使用验证码、对敏感数据如密码等进行加密、添加手机验证或邮箱验证等方法。

这些想法确实不错,我们尝试一下来实现它。

分析使用验证码:由于验证码有时效性,所以如果我们把验证码和账号密码存到一起的话,可能需要频繁地读写数据库,这样对系统的性能有很大的影响,所以我们可以把验证码单独拿出来,存放到redis中(或者session中),我们可以将id设为key,这样就能够高效地操作验证码了。对敏感数据进行加密:这个主要是防止数据库被不法分子盗取后,泄露掉用户密码,以及数据由前台传到后台的过程中,需要加密,防止爬虫。添加手机验证或邮箱验证:这个可以进一步绑定用户的信息,防止用户不小心泄露了密码后,被其他人登录。流程分析流程分析数据库设计在用户量少的时候,可能把账号密码和用户的基本信息放到同一张表上没什么问题,但如果用户量大了,或者说用户的基本信息字段多了,再放到一张表上,就显得有些臃肿了。

这时候,我们可以利用分库分表的思想,将单一的用户表user分为用户授权表user_auth和用户基础信息表user_basic。

分库分表的基本思想是将数据按照一定的规则分配到不同的数据库中,并且在每个数据库中再按照一定的规则将数据分配到不同的表中。这样,每个数据库和表的数据量都比较小,可以有效地提高数据库的查询速度和存储效率。

在user_auth表中,我们可以使用identifier来当做用户登录标识,credential当做用户秘钥,由于我们考虑到用户可能想通过不止一种方式登录(例如QQ、微信等),所以这里需要identity_type来当做用户标识类型。

user_basic表就不必多说了,存放着用户的个人信息,这个可以根据自己的项目来改进。

建表语句举例:

代码语言:sql复制/*

Navicat Premium Data Transfer

Source Server : localhostMySQL8

Source Server Type : MySQL

Source Server Version : 80032

Source Host : localhost:3307

Source Schema : rc

Target Server Type : MySQL

Target Server Version : 80032

File Encoding : 65001

Date: 17/09/2023 17:03:28

*/

SET NAMES utf8mb4;

SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------

-- Table structure for user_auth

-- ----------------------------

DROP TABLE IF EXISTS `user_auth`;

CREATE TABLE `user_auth` (

`id` bigint(0) NOT NULL,

`created_at` datetime(3) NULL DEFAULT NULL,

`updated_at` datetime(3) NULL DEFAULT NULL,

`deleted_at` datetime(3) NULL DEFAULT NULL,

`identity_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户标识类型(邮箱、手机号、token)',

`identifier` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户登录标识',

`credential` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户密钥',

`basic_id` bigint(0) UNSIGNED NULL DEFAULT NULL COMMENT 'basic表的id',

PRIMARY KEY (`id`) USING BTREE,

INDEX `idx_user_auth_deleted_at`(`deleted_at`) USING BTREE,

INDEX `fk_user_basic_auth_list`(`basic_id`) USING BTREE,

CONSTRAINT `fk_user_basic_auth_list` FOREIGN KEY (`basic_id`) REFERENCES `user_basic` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT

) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------

-- Table structure for user_basic

-- ----------------------------

DROP TABLE IF EXISTS `user_basic`;

CREATE TABLE `user_basic` (

`id` bigint(0) UNSIGNED NOT NULL AUTO_INCREMENT,

`created_at` datetime(3) NULL DEFAULT NULL,

`updated_at` datetime(3) NULL DEFAULT NULL,

`deleted_at` datetime(3) NULL DEFAULT NULL,

`uuid` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户唯一标识',

`nickname` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户昵称',

`avatar` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户头像',

`status` tinyint(1) NULL DEFAULT NULL COMMENT '用户状态',

`phone` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户手机号',

`email` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户邮箱',

`address` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户地址',

PRIMARY KEY (`id`) USING BTREE,

INDEX `idx_user_basic_deleted_at`(`deleted_at`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;考虑到SQL语句不直观,下面是我通过Navicat来可视化的表:

用户基础信息表 user_basic用户授权表 user_auth页面页面设计不在此次讨论的范围内,有想要代码的可以在评论区评论。

注册页面登录页面传输数据详情登录接口实现可以看到,在上图中,我们login接口只传输了一个info字段,是因为我们将账号和密码进行了加密,我的加密格式是这样的:

代码语言:text复制例如: identityType|identifier|credential -> 1|123456|mima666

第一步: 先分别AES加密identityType、identifier和credential。

第二步:将三个加密后的字段通过 “|” 分隔符合并成一个字段。

第三步:将合并后的字段进行RSA加密。这样的话,后端只需要先解密RSA,然后根据|分割字符串,然后再分别进行AES解密即可拿到原始数据。

项目代码由于种种原因,此项目只完成了登录注册功能就被搁浅了,目前正在打算一点一点的完善,此处贴出GitHub地址:https://github.com/rento666/rt-chat

TODO由于时间和篇幅有限,诸如扫码登录、判断IP是否为常住地、MFA校验等更加高级的方式没有探讨,此文章会持续更新,喜欢的可以点个赞、点个收藏。

参考『1』:HTML+CSS+JS实现十款好看的登录注册界面模板,赶紧收藏起来吧!我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表