全流程开发 | 高并发电商服务系统 | 第 6 关 | 登录模块开发

Posted 代码写注释

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了全流程开发 | 高并发电商服务系统 | 第 6 关 | 登录模块开发相关的知识,希望对你有一定的参考价值。

@TOC

0. 用户模块开发准备工作

电商 api 接口文档阅读

我们来学习一下用户的相应的管理,包括比如说登录,个人中心数据的修改,‌‌退出登录等等这些逻辑。

你可以在你本地搭建好测试的环境,因为我们的‌‌ API 接口或者说我们的业务逻辑开发完之后,我们需要在本地自测好,测完之后,我们需要把它上传到测试环境,‌‌给前/后端进行联调,比如说你给前端进行联调,你有一个联调环境,可以理解的是联调环境,

接下来我们需要去完成登录的场景,
请求 URL:
http://xx.com/api/login

登录我们需要 输入 手机号 和 短信验证码,
获取验证码完成之后,我们需要进行相应登录,登成功之后我们退跳转到首页,首页可以看到个人中心,你可以在个人中心这里修改资料,查看订单,修改收货地址等等,然后还有退出登录,这是我们‌‌接下来需要完成的工作。‌

‌我们在写登录逻辑之前,‌‌我们还需要用到一个东西,就是 API 文档,因为我们在开发之前需要前端和后端工程师进行相应的字段的规定,‌‌
文档可以参考:
电商 api 接口文档阅读

‌比如 如图:


通过接口文档,你可以具体的知道
请求方式是什么,‌‌
参数是什么,
返回的数据是什么,包括返回的数据的字段是什么意思,
这些 API 文档都需要我们自己去写。‌

‌比如说登录的时候我们的 API 是
http://xx.com/api/login
请求方式 是 POST,
然后有手机号,有验证码,‌‌还有 type,比如说默认的时候是保存多少天?7天 30天等等这些场景‌‌。

这些 API 文档都是需要大家写好,或者说跟前端工程师协商好,协商好完之后‌‌才对我们的业务进行相应的开发。‌

‌那么开发的时候我们需要在自己的环境当中测试好,比如说现在我开发完一个‌‌发送短信验证码的逻辑,我需要在我的环境当中自测好,自测好之后我再把它提交到联调环境,‌‌然后前端工程师就可以拿到它去联调了。‌

‌所以接下来我们需要去完成几个事情,
第一个事情就是要获取验证码,比如说我通过‌‌手机号去获取,那么获取验证码需要和第三方进行对接。‌
比如说和阿里云、腾讯云等等,
短信验证码获取到之后,我们就需要处理我们登录逻辑。‌

登录成功之后它会进入到我们的首页,‌‌
然后我们还需要有个人中心的页面,个人中心我们需要获取用户信息,修改用户的数据,然后‌‌还有 退出登录,这是我们需要完成的事情。

1. 用户表设计

关于用户表它是至关重要的,‌‌因为我们电商系统当中它离不开用户,所以我们必须要针对这个表进行设计。那么我们来看一下,‌‌设计好这张表叫mail_user,然后我们来过一下它里面的一些字段,‌‌
id
username
phone_number
password
litype
type
sex
create_time
update_time
status
operate_user

(1)
在 Fields 一栏中,
首先需要有 id,这毫无疑问,
它的 tpye 是 int,length 是 10 位,
Not Null 勾选,即不为空,
Key 是 1 个主键索引,‌‌
并且是自增的Auto Increment 和无符号的 Unsigned。‌

(2)
在 Fields 一栏中,
我们需要有用户名,
它的 type 是 varchar,length 是 100 位,
Not Null 勾选,即不为空,
用户名我们需要给出一个索引,‌‌
在 Indexes 一栏中,
Name 设置成 username,
Fields 设置成 "username"
Index Type 设置成 NORMAL。(这是可选字段)

(3)
手机号,因为我们系统当中‌‌会根据手机号加短信验证码的方式进行登录,所以说我们需要一个手机号,
它的 type 是 varchar,length 是 20 位,
为什么不用 int ?‌
‌是因为我们手机号可能还会考虑到 比如说别的国家的‌‌或者说海外港澳台的手机号等等 它前面是有个序号的,所以我们给一个 varchar 比较合理一点,‌‌

Not Null 勾选,即不为空,
因为我们会根据手机号加短信验证码的方式进行登录,‌‌我们就会用到根据手机号去查询我们库的数据,所以它和我们的 username 原理一样,也是需要设置一个索引,
在 Indexes 一栏中,
Name 设置成 phone_number,
Fields 设置成 "phone_number"
Index Type 设置成 NORMAL。(这是可选字段)

(4)
‌password 密码,因为我们可能会用到用户名和密码进行相应的登录。‌
它的 type 是 char,length 是 32 位,
Not Null 勾选,即不为空,

(5)
litype 登录方式,
它的 type 是 tinyint,length 是 1 位,
Not Null 勾选,即不为空,
Default Value 默认值是 0,同样它也是无符号的 Unsigned,
它是一个登录方式,‌‌比如说默认是 0,是手机号登录的,1 是 用户名密码登录,‌‌可能我们还有第三方登录,比如说微信登录、 QQ登录等等,支付宝登录等等,所以说我们有一个 litype

(6)
type 是会话保存天数,
它的 type 是 tinyint,length 是 1 位,
Not Null 勾选,即不为空,

因为我们后面做登录的时候会保存它的会话时间或者过期时间。‌

(7)
sex 性别,其实我们有几种场景,第一 男,‌‌第二 女,还有一个就是保密。
0 是保密,1 是男,2 是女。‌
它的 type 是 tinyint,length 是 1 位,
Not Null 勾选,即不为空,
Default Value 默认值是 0,同样它也是无符号的 Unsigned,

(8)
create_time | int | 10 | Not Null | 勾选
update_time | int | 10 | Not Null | 勾选
status | tinyint | 1 | Not Null | 勾选
operate_user | varchar | 100| Not Null | 勾选
Character Set 为 utf8,
Collation 为 utf8_general_ci。

以上就是表的设计。

‌设计好之后,我们就可以根据它表的结构,‌‌对我们前端或者说电商前端的用户行为,或者说用户的模块进行相应的这么一个操作,‌‌比如说登录,个人中心,修改用户的信息等等这些场景进行相应的开发。‌‌

2. 短信验证码记录到 redis

准备工作:
(1)开通阿里云短信服务。
(2)写好了生成 5 位 随机数 验证码的工具函数。

​然后我们需要把短信验证码记录到 redis 缓存中,并设置过期时间是 1 分钟。
具体做法是
拿到 code,通过 rand 函数。
拿到 sms_code,if 判断是否存在,如果存在则调用cache(手机号,验证码,过期时间)
然后 return sms_code。

redis 基础命令:
get 手机号
###》返回短信验证码

3. 用户登录的逻辑开发

这个过程我们需要输入手机号加验证码才能够进行登录,这个地方还有一个30天免密登录,‌‌你点击它之后相当于我们的 session 或者说token 会保存30天,是这么一种场景,

在我们开发逻辑之前,‌‌我们需要去定义好前端的 API 格式,需要后端工程师和前端工程师协商好 规范,‌‌那么这是我们写好的:
电商 api 接口文档阅读

需要规定 POST 的请求,‌‌
需要参数是手机号,‌验证码,
然后还有一个 type,type 相当于是保存的天数,7天 30天‌‌等等,
然后是它的返回值,

所以我们在写 API 之前必须要协商好,协商好之后,‌‌我们就严格按照这种规范去处理我们的场景。‌

‌那么在这个过程当中强调几件事情,‌‌我们传统的登录是会结合 cookie 和 session ,比如说在后端的管理当中,‌‌我们就用到了 session 登录,如果你的域名是保持一致的,是可以用 session 登录。‌

‌现在这种前后端分离一般是用 redis 加 token 的形式来处理登录的场景。‌‌
因为 redis 加 token 这种场景它能适用于所有的终端,比如说 Web端,‌‌这样的话我一个登录场景我就能适用于所有的逻辑,你 session 的话只能适用于 Web,‌‌所以本节我们要讲解的登录是基于 redis 加 token 的形式来处理我们的登录场景。‌

有些东西之前已经讲过了,比如说参数获取,‌‌比如处理它的一些校验。
然后我们组装 参数,最后我们利用 validate 机制去处理它的校验。‌

我们在之前说过控制器层职责只负责接收参数以及参数相应的校验,‌‌
然后把真正的逻辑我们放在 business 层。‌

你传递了手机号码,那么我们需要根据手机号码,‌‌然后去查询一下之前redis 当中的验证码,那么我怎么去做呢?‌‌
首先用$redisCode = catch(传递过来的手机号)方法,
我们需要去做个判断,‌‌判断什么?‌
如果 $redisCode 它是空的,或者不存在什么的,或者说不等于什么我们在页面中传递过来的 code ,‌
‌你输入 code 和我们缓存里面 code 不相等,那么这个时候我们认为是不合法的,或者说不成立,‌‌
然后给一个提示,不存在该验证码。‌
如果这些不成立说明你不能登录,如果能成立它就能够进行相应登录,是这么一个逻辑。

‌可以通过 Postman 工具来测试。​

登录我们之前说过,我们首先是需要‌‌去判断什么,去判断我们表里面是否有用户记录,‌‌
这个用户记录你就可以通过 phone_number 去查,因为现在我们是通过手机号‌‌加短信验证码的方式去处理我们的登录逻辑,所以我们根据 ta 去查询就可以了。‌

‌如果有‌‌我们就更新,如果没有我们就新增一条记录,然后我们还需要什么,我们还需要去生成一个 token,‌‌因为我们是用 token 加 redis 的方式去登录的,
比如说用户的 ID,用户名,我们记录到 redis 里面去,是这么一种逻辑,‌‌这个时候我们来这样写,首先我们需要去根据手机号码去获取用户的信息。‌

写上 function getUserByPhoneNumber($phone_number),
这时候我们需要做一个判断,比如说如果它的值不存在,那么返回一个false ,
然后 where 以 phone_number 为参数 查询 find(),
然后返回值用 result 接受就可以了。

怎么去获取用户信息?
调用 getUserByPhoneNumber($phone_number),传递我们的$phone_number,‌‌
然后赋给一个变量,比如叫做 user,
这个时候我们判断一下 user 是否存在‌‌。

如果不存在,我们就需要去新增一条记录,我给一个 $user_data,‌‌
我需要新增,mall_user 表里面我需要新增哪些值,
username
phonenumber
password 用不到,因为我们不是用的密码来登录的,我们是用到手机号 加 验证码,
‌然后 type,然后 性别‌‌ , 时间,状态等,
因为 第一次 他就没有用户名,我给他生成默认的一个用户名,比如说mail
拼接 手机号,


‌我们再来看一下,如果不存在,我们说新增一条逻辑,然后再来刷新一下,看这个数据库有没有新增,‌‌我刷新一遍,就新增了,并且我们的什么创建时间,更新时间都自动带了,‌‌因为我们的设置,它就会自动的去写入创建时间和更新时间。‌

用户存在这个时候我们只需要做更新就可以了,‌‌更新我们的表结构,
比如说更新它的更新时间,你还可以加这么一个字段,‌‌加上 最后登录时间,最后登录的 IP 。‌

‌这个时候 我们是可以获取到或者说可以拿到它的相应的数据。‌‌
接下来有这些数据之后,我们就需要对我们的数据进行相应的处理,比如说 我肯‌‌还要把 token 涉及到的比如说它的用户 ID,用户名相关信息我们记录到 redis 里面去,‌‌后续登录的时候,我们只关注 redis 里面数据就可以了。​

4. 用户登录逻辑-基于 redis 加 token

用 token 主要是为了后续我们能够适用于多终端,这也是当前比较流行的一种登录方式,这是需要我们去关注的。

高并发的场景,我们的用户登录的基本信息放到 redis 里面,要优于放到 mysql 里面去,因为我们的场景,‌‌你获取用户的基本信息不会很多,但是我们要判断用户是否登录,‌‌这种场景就很多了,所以说我们要把它抽离出来放到 redis 里面去。

首先我们需要去 获取 token,写个方法叫做生成登录所需的token,叫getLoginToken($string),‌‌然后传递一个字段,传递一个变量,怎么生成‌‌,我是通过 md5()这种形式来生成一个不会重复的一个字符串,
然后再根据这个字符串‌‌加上我传递的这么一个参数,通过sha1(拼接字符串)来进行一个加密,最终返回 token。‌

怎么用 token ?
我需要去记录两个信息,
(1)
userId
(2)
username

‌怎么去记录?
用cache($token,$redisData),返回值 res 接受 cache($token,$redisData)。
这时候我们需要判断,当如果返回值存在‌‌,我们就返回 token 和 username,否则我返回 false。

为什么我要返回这种场景?‌
‌因为登录成功之后,我要把这个数据给前端,它就会把这个 token 和username 记录它的本地,
这是前端需要的一种格式,所以我们必须要返回数据。‌

‌做完之后可在 postman 中 做测试。

在 redis 终端看下有没有 token 数据。

后续我们就可以根据它‌‌来处理我们的逻辑了,
因为这样的话,其实它会把我们的相应的数据返回来,比如说登录成功之后会返回 token 和 username,‌‌

前端它就会把数据会记录到浏览器本地缓存里面,
后续它就拿到这个 token 进行后续的请求。‌

‌后端就根据 token 去 redis 里面去查数据,
但是我们这个地方还需要做个优化,因为我们需要去给出它的失效时间,‌‌所以说我们需要去创建需要失效时间的逻辑。(expiretime)

它的时间在 catch 方法里面‌‌是写在第三个参数。‌

在 postman 中 我们再来做个测试,
在 redis 终端中 获取 token。

前端,我登录点击之后,不能让它重复的去点击,但是‌‌因为接口是能暴露给用户的,用户如果一直去请求接口,这样的话我们就生成很多脏的token,
如何去做大家可以去思考一下。
解决方案后续会介绍。
‌​

以上是关于全流程开发 | 高并发电商服务系统 | 第 6 关 | 登录模块开发的主要内容,如果未能解决你的问题,请参考以下文章

全流程开发 GO实战电商网站高并发秒杀系统 百度云

一个基于SSM框架开发的高并发电商秒杀Web系统

第6期-PHP电商网站高并发秘诀之异步消息队列

5天火速上线疫情防控项目,高并发全靠缓存来扛(长文分享)!

亿级流量电商详情页系统实战-缓存架构+高可用服务架构+微服务架构第二版视频教程

电商双十一秒杀系统(高并发企业级项目)开发视频教程