前端访问个人信息页面时,需要向后端请求个人信息。
在本页面中要显示用户的Email邮箱信息,而对于邮箱信息我们要实现对于邮箱的验证功能,并在本页面中显示邮箱是否已验证,如下所示,
由上图可知,我们需要在User模型类中增加一个邮箱是否验证的字段:
class User(AbstractUser):
"""
用户信息
"""
mobile = models.CharField(max_length=11, unique=True, verbose_name="手机号")
email_active = models.BooleanField(default=False, verbose_name='邮箱验证状态')
请求方式: GET /user/
请求参数: token(headers中)
返回数据: JSON
返回值 | 类型 | 是否必须 | 说明 |
---|---|---|---|
id | int | 是 | 用户id |
username | str | 是 | 用户名 |
mobile | str | 是 | 手机号 |
str | 是 | email邮箱 | |
email_active | bool | 是 | 邮箱是否通过验证 |
定义一个序列化器,用来序列化返回用户数据
# users/serializers.py
class UserDetailSerializer(serializers.ModelSerializer):
"""
用户详细信息序列化器
"""
class Meta:
model = User
fields = ('id', 'username', 'mobile', 'email', 'email_active')
# user/views.py
# url(r'^user/$', views.UserDetailView.as_view()),
class UserDetailView(RetrieveAPIView):
"""用户详情"""
serializer_class = UserDetailSerializer
permission_classes = [IsAuthenticated] # 用户验证
def get_object(self):
"""
重写get_object,不使用pk值返回user
:return:
"""
return self.request.user
注意:访问视图必须要求用户已通过认证(即登录之后)
在用户中心页面中,允许用户设置邮箱
当用户点击保存后,我们会向用户发送邮件以验证邮箱的有效性。
为了避免用户未收到验证邮箱,我们提供“重新发送验证邮件”按钮允许用户重新发送邮件。
邮箱验证成功,显示已验证
在邮件中提供的激活链接地址,为了能区分是哪个用户在进行邮箱验证,需要在链接找那个包含用户和邮箱的识别信息,如user_id和email数据,但是基于安全性的开率,不能将这两个数据直接暴露在邮件链接中,而是需要进行隐藏和签名处理(能够检测出是否修改过链接数据)。可以使用前面学习过的itsdangerous对user_id和email数据进行处理,生成token作为连接的参数。
Django中内置了邮件发送功能,被定义在django.core.mail模块中。发送邮件需要使用SMTO服务器,常用的免费服务器有:163,126,QQ, 其中以163邮件为例。
# Django的邮箱配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
#发送邮件的邮箱
EMAIL_HOST_USER = '135****[email protected]'
#在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'test001'
#收件人看到的发件人
EMAIL_FROM = 'meiduo<135****[email protected]>'
在django.core.mail模块提供了send_mail来发送邮件.
send_mail(subject, message, from_email, recipient_list, html_message=None)
例如:
msg='<a href="http://www.itcast.cn/subject/pythonzly/index.shtml" target="_blank">点击激活a>'
send_mail('注册激活','',settings.EMAIL_FROM, ['135****[email protected]@163.com'], html_message=msg)
请求方式: PUT /email/
请求参数: JSON或表单
参数 | 类型 | 是否必须 | 说明 |
---|---|---|---|
str | 是 | email邮箱 |
返回数据: JSON
返回值 | 类型 | 是否必须 | 说明 |
---|---|---|---|
id | int | 是 | 用户ID |
str | 是 | 用户邮箱 |
在user/serializers.py中定义新的序列化器,验证用户提交的邮箱信息。
# user/serializers.py
class EmailSerializer(serializers.ModelSerializer):
"""保存邮箱序列化器"""
class Meta:
model = User
fields = ('id', 'email')
extra_kwargs = {
'email':{
'required':True # 是否必传
}
}
def update(self, instance, validated_data):
"""
更新邮箱到用户字段
:param instance:
:param validated_data:
:return:
"""
instance.email = validated_data["email"]
instance.save()
return instance
在user/views.py中创建新视图,用于保存用户的邮箱信息,注意需要用户登录通过认证后.
# /user/views.py
class EmailView(UpdateAPIView):
"""
保存用户邮箱
"""
permission_classes = [IsAuthenticated] # 验证用户登录
serializer_class = EmailSerializer
def get_object(self, *args, **kwargs):
"""
重写get_object方法,获取当前用户对象
update()中需要get_object获
:param args:
:param kwargs:
:return:
"""
return self.request.user
设置路由信息:
url(r'^email/$', views.EmailView.as_view()), # 设置邮箱
在保存邮箱的时候,需要向用户发送验证邮件,我们将发送邮件的工作放到celery中异步执行。
在celert_tasks目录中新建email目录、email/init.py和email/asks.py文件
在email/tasks.py文件中是实现发送邮件的异步任务:
# -*-coding:utf-8-*-
# celert_tasks/email/tasks.py
from celery_tasks.main import app
from django.core.mail import send_mail
from django.conf import settings
@app.task(name='send_verify_email')
def send_verify_email(to_email, verify_url):
"""
发送验证邮箱的邮件
:param to_mail: 收件人邮箱
:param verify_url: 验证链接
:return:
"""
subject = "美多商城邮箱验证"
html_message = '尊敬的用户您好!
' \
'感谢您使用美多商城。
' \
'您的邮箱为:%s 。请点击此链接激活您的邮箱:
' \
'' % (to_email, verify_url, verify_url)
# 发送邮件
send_mail(subject,"",settings.EMAIL_FROM, [to_email], html_message=html_message)
注意:
在发送邮件的异步任务中,需要用到django的配置文件,所以我们需要修改celery的启动文件main.py,在其中指明celery可以读取的django配置文件,并且注册添加email的任务
# celert_tasks/main.py
...
# 自动注册celery任务
app.autodiscover_tasks([
'celery_tasks.sms',
'celery_tasks.tasks',
])
在User子应用的序列化器类中定义生成验证邮箱链接的方法
邮箱的激活链接是用户点击时会访问的网址,我们让用户点击时进入到success_verify_email.html页面。
# apps/users/serializers/EmailSerializer
def generate_verify_email_url(self,instance):
"""
生成验证邮箱的url
:return:
"""
tjs = TJS(settings.SECRET_KEY, 300)
token = tjs.dumps({"name":instance.username}).decode()
verify_url = 'http://www.meiduo.site:8080/success_verify_email.html?token=' + token
return verify_url
修改EmailSerializer序列化器的update方法,增加发送邮件
# apps/users/serializers/EmailSerializer
def update(self, instance, validated_data):
"""
更新邮箱到用户字段
:param instance:
:param validated_data:
:return:
"""
instance.email = validated_data["email"]
instance.save()
# 生成验证url
verify_url = self.generate_verify_email_url(instance)
email = instance.email
# 异步发送邮件
send_verify_email.delay(email, verify_url)
return instance
当用户点击邮箱里的链接时,进入到success_verify_email.html页面。
在该页面中,我们将请求网址中用于验证的token发送给后端接口,由后端接口判断token的有效性,如果token有效,则修改邮箱的验证状态,并将处理结果返回给前端展示给用户。
请求方式: GET emails/verification/?token= ****
请求参数: 查询字符串
参数 | 类型 | 是否必须 | 说明 |
---|---|---|---|
token | str | 是 | 用于验证邮箱的token |
返回数据: JSON
返回值 | 类型 | 是否必须 | 说明 |
---|---|---|---|
message | str | 是 | 验证处理结果 |
在users/views.py中新建视图:
# apps/users/views.py
class VerifyEmailView(APIView):
"""验证邮箱"""
def get(self, request):
"""
验证邮箱,将用户数据中的邮箱状态置为真
:param request:
:return:
"""
# 获取token
token = request.query_params.get('token')
tjs = TJS(settings.SECRET_KEY, 300)
try:
data = tjs.loads(token)
except:
return Response({"errors":"token无效"}, status=status.HTTP_400_BAD_REQUEST)
# 查找用户
username = data.get("username")
print("username:{}".format(username))
try:
user = User.objects.get(username=username)
except:
return Response({"errors":"用户不存在"},status=status.HTTP_400_BAD_REQUEST)
# 更改用户邮箱验证状态
user.email_active = True
user.save()
return Response({"message":True})
配置路由:
url(r"^emails/verification/$",views.VerifyEmailView.as_view()),