3.2 KiB
3.2 KiB
邮箱验证双重验证实现计划
需求总结
在找回密码功能中,用户可能使用虚假邮箱(如 test@example.com)导致邮件被退回。需要在发送前验证邮箱真实性,避免无效发送。
当前状态分析
前端(ForgotPassword.tsx)
- 仅验证邮箱是否为空
- 无格式验证
- 无"必须使用真实邮箱"提示
后端(user/views/user.py)
ForgotPasswordSendCodeAPIView仅验证邮箱是否为空- 直接调用
FUser.objects.filter(email=to_email).first()查询用户 - 若用户不存在,返回
USER_NOT_FOUND错误 - 无 MX 记录验证
实现方案
1. 前端验证
文件:src/pages/ForgotPassword/ForgotPassword.tsx
修改内容:
- 增加邮箱格式验证(使用正则表达式)
- 发送前弹出确认提示:"请确保使用真实邮箱,验证码将发送至该邮箱"
- 前端验证不通过时不发送请求
const handleSendCode = async () => {
if (!email) {
message.warning(t('forgotPassword.warnEmailRequired'));
return;
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
message.warning(t('forgotPassword.warnEmailFormat'));
return;
}
// 继续发送...
};
新增翻译文本:
warnEmailFormat: "邮箱格式不正确"confirmSend: "验证码将发送至该邮箱,请确认是真实邮箱"
2. 后端 MX 记录验证
文件:user/views/user.py
修改内容:
- 在
ForgotPasswordSendCodeAPIView.post()中增加 MX 记录验证 - 使用 Python
socket或dns.resolver库查询 MX 记录 - 若 MX 记录不存在,直接返回错误
import socket
def validate_email_mx(email):
"""验证邮箱域名是否有MX记录"""
try:
domain = email.split('@')[1]
mx_records = socket.getaddrinfo(domain, None, socket.AF_INET, socket.SOCK_STREAM)
return len(mx_records) > 0
except (socket.gaierror, IndexError):
return False
注意:QQ Mail 对无效域名会退信,MX 验证可以在发送前拦截。
3. 涉及文件
| 文件 | 修改类型 | 说明 |
|---|---|---|
src/pages/ForgotPassword/ForgotPassword.tsx |
修改 | 增加格式验证和提示 |
user/views/user.py |
修改 | 增加 MX 记录验证 |
src/locales/zh.json |
修改 | 添加错误提示文本 |
验证步骤
-
前端格式验证
- 输入
test(无@符号)→ 提示格式错误 - 输入
test@example.com→ 继续验证 - 输入
test@nonexistent-domain-xyz.com→ 后端MX验证拦截
- 输入
-
后端 MX 验证
- 输入
test@example.com→ MX 不存在,返回错误 - 输入
test@qq.com→ MX 存在,继续发送 - 输入
test@gmail.com→ MX 存在,继续发送
- 输入
-
端到端测试
- 使用真实邮箱
test@qq.com测试完整流程 - 确认收到验证码邮件
- 使用真实邮箱
备选方案
如果 MX 验证过于严格(可能误杀某些特殊域名),可以考虑:
- 仅在前端提示,不拦截
- 或添加白名单机制
- 或使用第三方邮箱验证 API
注意事项
- MX 验证需要 DNS 查询,可能增加约 100ms 延迟
- 建议结合缓存避免重复查询
- 仅对找回密码等关键场景启用