-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
111 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
# 实现一个邮箱辅助登录功能 | ||
|
||
## 痛点 | ||
|
||
如果有自己折腾一些自己的网站,或者做毕设的同学,相信你们一定都遇到过这么一个问题:注册时,想用微信号、手机号、邮箱来辅助登录,但是不知道怎么接入到我们的系统中,亦或是要收费。 | ||
|
||
> - 接入微信开放平台网页登录收费。 | ||
> - 手机号短信服务收费。 | ||
> - **邮件服务,我们即可自己实现。** | ||
我前后做了好几个小工具或者网站,这个问题技术问题一直没有被突破,近期终于实现了邮箱验证码系统。并接入了 [DODD](https://tdl.jimmyxuexue.top/#/center) 中。 | ||
|
||
## 效果 | ||
|
||
效果如下: | ||
|
||
![image-20231212110242628](https://image.jimmyxuexue.top/img/202312121102770.png) | ||
|
||
对应的邮箱会收到这么一条信息: | ||
|
||
![image-20231212110424010](https://image.jimmyxuexue.top/img/202312121104097.png) | ||
|
||
![image-20231212110500300](https://image.jimmyxuexue.top/img/202312121105345.png) | ||
|
||
将此验证码输入之后,便可登录系统,获取对应的用户信息。 | ||
|
||
## 实现思路 | ||
|
||
下面我们来说说实现思路,整体上我们是需要解决这么两个问题: | ||
|
||
- 通过代码的方式发送邮件。 | ||
- 将验证码&发送用户与系统进行关联,进行一些校验的逻辑。 | ||
|
||
### 发送邮件 | ||
|
||
之前 B 站上传过一个视频,讲了如何发送邮件,附上传送门 🚪:[nodejs 实现邮件服务](https://www.bilibili.com/video/BV1Dz4y1G7wm/?vd_source=b869b9e47469b5438851429bda1fb3fc) | ||
|
||
<iframe src="//player.bilibili.com/player.html?aid=576691965&bvid=BV1Dz4y1G7wm&cid=1285265826&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe> | ||
|
||
核心就是通过 [nodemailer](https://www.npmjs.com/package/nodemailer) 这个库,去帮助我们发送一些邮件。 | ||
|
||
> 这个库的核心也是去调用一些邮箱的公共接口,所以我们是需要获取自己账号的 token,并且开放一些高级权限的。 | ||
具体的如何操作不在这篇内容做详细记录,大家自行过一遍视频即可。 | ||
|
||
### 与现有系统进行关联 | ||
|
||
> 作为一名前端程序员 👨🏻💻,所以这一块的实现可能会有并不是非常合理的地方,还望大家可以提出更好的方案。 | ||
这里我们需要借助`redis`,之所以使用`redis`而不用`mysql`是因为它拥有更快的速度。 | ||
|
||
所以我们需要维护这么一个数据结构。key 为:`snow-server-mail-verification-code-邮箱地址`,值为随机六位数验证码。同事设置过期时间为 10 分钟。 | ||
|
||
> 设置了 10 分钟后,redis 会自动为我们清空掉这个 key | ||
```ts | ||
@Post('send_verification_code') | ||
async send(@Body() body: SendMailDto) { | ||
const { mail } = body; | ||
if (!isQQMail(mail)) { | ||
return { code: 500, result: '邮箱格式不正确 - 不是qq邮箱' }; | ||
} | ||
const redis = await RedisInstance.initRedis(); | ||
const code = generateRandomCode(); | ||
const key = `snow-server-mail-verification-code-${mail}`; | ||
redis.set(key, code); | ||
redis.expire(key, 600); // 单位是秒 | ||
await this.nodemailerService.sendVerificationCode({ to: mail, code }); | ||
return { code: 200, result: '发送成功' }; | ||
} | ||
``` | ||
|
||
设置上了这么个 key 之后,我们就可以在登录的时候拿上这个验证码和 key 校验一下`redis`中这个 key 是否一致,如果一致,则校验通过,给于登录的 token 之类的权限。 | ||
|
||
部分代码如下: | ||
|
||
```ts | ||
@Post('login_by_mail') | ||
async loginByMail(@Body() body: LoginByMailDto) { | ||
const { code, mail } = body; | ||
if (!isQQMail(mail)) { | ||
return { code: 500, result: '邮箱格式验证异常,请校验' }; | ||
} | ||
let user = await this.usersService.findUserByMail(mail); | ||
if (!user) { | ||
return { | ||
code: 10000, | ||
result: '该邮箱未创建用户,请检查地址,或为该邮箱注册一个用户', | ||
}; | ||
} | ||
const redis = await RedisInstance.initRedis(); | ||
const key = `snow-server-mail-verification-code-${mail}`; | ||
const redisCode = await redis.get(key); | ||
if (redisCode !== code.toUpperCase()) { | ||
return { | ||
code: 500, | ||
result: '验证码校验失败,请重新发送验证码进行校验', | ||
}; | ||
} | ||
if (redisCode) { | ||
await redis.del(key); | ||
} | ||
return await this.usersService.createToken(user); | ||
} | ||
``` | ||
|
||
## 总结 | ||
|
||
基于以上的两个关键步骤,我们就能够在自己的系统中接入邮箱辅助登录的服务了。对于想要自己动手做一个自己网站之类的东西还是挺不错的。 | ||
|
||
感谢观看。有不清晰的地方欢迎私信。 |