|
|
|
|
@ -1,49 +1,79 @@
|
|
|
|
|
import typing
|
|
|
|
|
from datetime import timedelta
|
|
|
|
|
|
|
|
|
|
from django.core.cache import cache
|
|
|
|
|
from django.core.cache import cache # Django缓存框架,用于存储验证码(内存/Redis等,由项目配置决定)
|
|
|
|
|
from django.utils.translation import gettext
|
|
|
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
|
from django.utils.translation import gettext_lazy as _ # 国际化支持,用于生成多语言提示文本
|
|
|
|
|
|
|
|
|
|
from djangoblog.utils import send_email
|
|
|
|
|
from djangoblog.utils import send_email # 导入项目公共邮件发送工具函数
|
|
|
|
|
|
|
|
|
|
_code_ttl = timedelta(minutes=5)
|
|
|
|
|
_code_ttl = timedelta(minutes=5) # 验证码有效期:5分钟(全局常量,统一控制验证码过期时间)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def send_verify_email(to_mail: str, code: str, subject: str = _("Verify Email")):
|
|
|
|
|
"""发送重设密码验证码
|
|
|
|
|
"""
|
|
|
|
|
发送密码重置验证邮件(核心功能:向目标邮箱发送含验证码的邮件)
|
|
|
|
|
邮件内容支持国际化,验证码有效期与全局常量`_code_ttl`保持一致(5分钟)
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
to_mail: 接受邮箱
|
|
|
|
|
subject: 邮件主题
|
|
|
|
|
code: 验证码
|
|
|
|
|
to_mail: 接收邮件的目标邮箱地址(字符串类型,需符合邮箱格式)
|
|
|
|
|
code: 生成的随机验证码(字符串类型,用于后续密码重置验证)
|
|
|
|
|
subject: 邮件主题(可选参数,默认值为国际化的"Verify Email",支持多语言切换)
|
|
|
|
|
"""
|
|
|
|
|
# 构建邮件HTML内容(国际化模板,通过占位符注入验证码,明确告知有效期)
|
|
|
|
|
html_content = _(
|
|
|
|
|
"You are resetting the password, the verification code is:%(code)s, valid within 5 minutes, please keep it "
|
|
|
|
|
"properly") % {'code': code}
|
|
|
|
|
# 调用项目公共邮件发送函数,发送验证码邮件(收件人列表、主题、HTML内容)
|
|
|
|
|
send_email([to_mail], subject, html_content)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def verify(email: str, code: str) -> typing.Optional[str]:
|
|
|
|
|
"""验证code是否有效
|
|
|
|
|
"""
|
|
|
|
|
验证验证码的有效性(核心功能:校验用户输入的验证码与缓存中存储的是否一致)
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
email: 请求邮箱
|
|
|
|
|
code: 验证码
|
|
|
|
|
email: 待验证的邮箱地址(与验证码绑定的唯一标识,确保验证码针对性)
|
|
|
|
|
code: 用户输入的验证码(需与缓存中存储的验证码比对)
|
|
|
|
|
|
|
|
|
|
Return:
|
|
|
|
|
如果有错误就返回错误str
|
|
|
|
|
Node:
|
|
|
|
|
这里的错误处理不太合理,应该采用raise抛出
|
|
|
|
|
否测调用方也需要对error进行处理
|
|
|
|
|
验证失败返回错误提示字符串(支持国际化),验证成功返回None
|
|
|
|
|
|
|
|
|
|
Note:
|
|
|
|
|
1. 原代码注释保留:当前错误处理逻辑不合理,建议改用raise抛出异常(而非返回错误字符串),
|
|
|
|
|
便于调用方统一捕获和处理,减少错误处理冗余;
|
|
|
|
|
2. 验证码校验逻辑:通过邮箱作为缓存key,获取存储的验证码,与输入值直接比对(大小写敏感);
|
|
|
|
|
3. 若缓存中无该邮箱对应的验证码(如过期、未发送),则默认返回验证码错误提示。
|
|
|
|
|
"""
|
|
|
|
|
# 从缓存中获取该邮箱对应的验证码(缓存key为邮箱地址,value为之前存储的验证码)
|
|
|
|
|
cache_code = get_code(email)
|
|
|
|
|
# 比对缓存中的验证码与用户输入的验证码,不一致则返回错误提示
|
|
|
|
|
if cache_code != code:
|
|
|
|
|
return gettext("Verification code error")
|
|
|
|
|
return gettext("Verification code error") # 国际化的验证码错误提示
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_code(email: str, code: str):
|
|
|
|
|
"""设置code"""
|
|
|
|
|
"""
|
|
|
|
|
将邮箱与验证码绑定并存储到缓存中(核心功能:为后续验证提供数据支持)
|
|
|
|
|
存储时自动设置过期时间(与全局`_code_ttl`一致,5分钟),避免验证码永久有效
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
email: 验证码绑定的邮箱地址(作为缓存的唯一key,确保一对一关联)
|
|
|
|
|
code: 需存储的随机验证码(字符串类型,建议由`generate_code`等工具函数生成)
|
|
|
|
|
"""
|
|
|
|
|
# 缓存存储:key=邮箱地址,value=验证码,timeout=有效期(秒数,由_timedelta转换)
|
|
|
|
|
cache.set(email, code, _code_ttl.seconds)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_code(email: str) -> typing.Optional[str]:
|
|
|
|
|
"""获取code"""
|
|
|
|
|
return cache.get(email)
|
|
|
|
|
"""
|
|
|
|
|
从缓存中获取指定邮箱对应的验证码(核心功能:为验证码校验提供数据源)
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
email: 目标邮箱地址(缓存key,用于精准获取绑定的验证码)
|
|
|
|
|
|
|
|
|
|
Return:
|
|
|
|
|
缓存中存在该邮箱对应的验证码则返回字符串类型的验证码,否则返回None(如过期、未存储)
|
|
|
|
|
"""
|
|
|
|
|
# 从缓存中获取值:key为邮箱地址,不存在或过期时返回None
|
|
|
|
|
return cache.get(email)
|