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

一卷旌收千骑虏,万全身出百重围。这篇文章主要讲述全流程开发 | 高并发电商服务系统 | 第 6 关 | 登录模块开发相关的知识,希望能为你提供帮助。
@TOC
0. 用户模块开发准备工作电商 api 接口文档阅读
我们来学习一下用户的相应的管理,包括比如说登录,个人中心数据的修改,??退出登录等等这些逻辑。
你可以在你本地搭建好测试的环境,因为我们的?? API 接口或者说我们的业务逻辑开发完之后,我们需要在本地自测好,测完之后,我们需要把它上传到测试环境,??给前/后端进行联调,比如说你给前端进行联调,你有一个联调环境,可以理解的是联调环境,
接下来我们需要去完成登录的场景,
请求 URL:
http://xx.com/api/login
登录我们需要 输入 手机号 和 短信验证码,
获取验证码完成之后,我们需要进行相应登录,登成功之后我们退跳转到首页,首页可以看到个人中心,你可以在个人中心这里修改资料,查看订单,修改收货地址等等,然后还有退出登录,这是我们??接下来需要完成的工作。?
?我们在写登录逻辑之前,??我们还需要用到一个东西,就是 API 文档,因为我们在开发之前需要前端和后端工程师进行相应的字段的规定,??
文档可以参考:
电商 api 接口文档阅读
?比如 如图:

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

文章图片

通过接口文档,你可以具体的知道
请求方式是什么,??
参数是什么,
返回的数据是什么,包括返回的数据的字段是什么意思,
这些 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. 用户登录的逻辑开发
全流程开发 | 高并发电商服务系统 | 第 6 关 | 登录模块开发

文章图片

这个过程我们需要输入手机号加验证码才能够进行登录,这个地方还有一个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。
【全流程开发 | 高并发电商服务系统 | 第 6 关 | 登录模块开发】前端,我登录点击之后,不能让它重复的去点击,但是??因为接口是能暴露给用户的,用户如果一直去请求接口,这样的话我们就生成很多脏的token,
如何去做大家可以去思考一下。
解决方案后续会介绍。
??

    推荐阅读