Django发送邮件及邮件激活
Posted cl-python
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django发送邮件及邮件激活相关的知识,希望对你有一定的参考价值。
根据前端请求头中传入的JWT token的信息,使用DRF中追加的JWT认证判断是否登录
axios.get(this.host + ‘/user/‘, { // 向后端传递JWT token的方法 headers: { ‘Authorization‘: ‘JWT ‘ + this.token }, responseType: ‘json‘, })
在settins配置文件中添加配置DRF的JWT
# 配置DRF REST_FRAMEWORK = { # 异常处理 ‘EXCEPTION_HANDLER‘: ‘meiduo_mall.utils.exceptions.exception_handler‘, #配置JWT作为验证的后端 ‘DEFAULT_AUTHENTICATION_CLASSES‘: ( ‘rest_framework_jwt.authentication.JSONWebTokenAuthentication‘, ‘rest_framework.authentication.SessionAuthentication‘, ‘rest_framework.authentication.BasicAuthentication‘, ), }
在users/models.py文件中,修改User模型类,增加邮箱是否验证的字段
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
"""用户模型类"""
email_active = models.BooleanField(default=False, verbose_name=‘邮箱验证状态‘) # 默认邮件未激活
class Meta:
db_table = ‘tb_users‘
verbose_name = ‘用户‘
verbose_name_plural = verbose_name
使用迁移命令,迁移模型类在数据库中以表格形式展示
python manage.py makemigrations
python manage.py migrate
在users/urls.py文件中添加路由
urlpatterns=[
# 获取登录用户的详情信息
url(r‘^user/$‘, views.UserDetailView.as_view()),
]
在users/views.py 中新建视图
from rest_framework.generics import RetrieveAPIView
from rest_framework.permissions import IsAuthenticated
from . import serializers
# url(r‘^user/$‘, views.UserDetailView.as_view()),
class UserDetailView(RetrieveAPIView):
"""提供登录用户的详情的"""
# 指定序列化器
serializer_class = serializers.UserDetailSerializer
# IsAuthenticated 采用的是JWT的验证
# 用户身份验证:是否是登录用户
permission_classes = [IsAuthenticated]
def get_object(self):
"""返回当前谁是登录用户
为什么要重写该方法:是因为我们的路由没有主键
返回的user是JWT验证系统验证后的登录用户
"""
return self.request.user
注意:访问视图必须要求用户已通过认证(即登录之后)
在users/serializers.py中创建序列化器
from rest_framework import serializers
from .models import User
class UserDetailSerializer(serializers.ModelSerializer):
"""用户详细信息序列化器"""
class Meta:
model = User
# 只负责输出,并指定输出的字段
fields = (‘id‘, ‘username‘, ‘mobile‘, ‘email‘, ‘email_active‘)
Django中内置了邮件发送功能,被定义在django.core.mail模块中。发送邮件需要使用SMTP服务器,常用的免费服务器有:163、126、QQ ,先设置一个邮箱为邮件服务器,可以设置自己的邮箱为邮件服务器,下面以163邮件为例,操作步骤如下:
1)注册163邮箱itcast88,登录后设置。
2)在新页面中点击“客户端授权密码”,勾选“开启”,弹出新窗口填写手机验证码。
3)填写授权码。
4)提示开启成功。
接下来需要在项目的Django配置文件settings中,设置邮箱的配置信息:
# 配置邮件服务器
EMAIL_BACKEND = ‘django.core.mail.backends.smtp.EmailBackend‘ # 导入邮件模块
EMAIL_HOST = ‘smtp.163.com‘ # 发邮件主机
EMAIL_PORT = 25 # 发邮件端口
EMAIL_HOST_USER = ‘itcast11@163.com‘ # 授权的邮箱
EMAIL_HOST_PASSWORD = ‘python808
‘# 邮箱授权时获得的密码,非注册登录密码
EMAIL_FROM = ‘python<[email protected]>‘# 发件人抬头
在users/views.py中创建新视图,用于保存用户的邮箱信息,注意需要用户登录通过认证后。
from rest_framework.generics import UpdateAPIView from rest_framework.permissions import IsAuthenticated # url(r‘^email/$‘, views.EmailView.as_view()), class EmailView(UpdateAPIView): """更新邮件""" # 验证用户身份信息 permission_classes = [IsAuthenticated] # 指定序列化器 serializer_class = serializers.EmailSerializer def get_object(self): return self.request.user
在users/urls.py文件中设置添加邮箱的路由信息:
urlpatterns = [
url(r‘^email/$‘, views.EmailView.as_view()),
]
在users/serializers.py中新建序列化器,用户验证用户提交的邮箱信息。
from rest_framework import serializers from celery_tasks.email.tasks import send_verify_email class EmailSerializer(serializers.ModelSerializer): """ 邮箱序列化器 """ class Meta: model = User fields = (‘id‘, ‘email‘) extra_kwargs = { ‘email‘: { ‘required‘: True } } def update(self, instance, validated_data):
# 当前的user模型类调用email字段,将经过验证的email保存到这个字段里面 instance.email = validated_data[‘email‘] instance.save() # instance 就表示前面指定的User # 在完成保存数据的返回之前,生成邮件激活的连接 verify_url = instance.generate_verify_email_url() # 发送激活邮件 send_verify_email.delay(instance.email, verify_url) return instance
补充发送验证邮件
在django.core.mail
模块提供了send_mail
来发送邮件。
send_mail
(subject, message, from_email, recipient_list,html_message=None)
- subject 邮件标题
- message 普通邮件正文, 普通字符串
- from_email 发件人
- recipient_list 收件人列表
- html_message 多媒体邮件正文,可以是html字符串
例如:
msg=‘<a href="http://www.itcast.cn/subject/pythonzly/index.shtml" target="_blank">点击激活</a>‘
send_mail(‘注册激活‘,‘‘,settings.EMAIL_FROM, [‘[email protected]‘], html_message=msg)
在保存邮箱的时候,需要向用户发送验证邮件,我们将发送邮件的工作放到celery中异步执行。
在celerytasks目录中新建email目录和`email/_init.py文件和
email/tasks.py`文件
在email/tasks.py
文件中实现发送邮件的异步任务
from django.core.mail import send_mail from django.conf import settings from celery_tasks.main import celery_app @celery_app.task(name=‘send_verify_email‘) def send_verify_email(to_email, verify_url): """ 发送验证邮箱邮件 :param to_email: 收件人邮箱 :param verify_url: 验证链接 :return: None """ subject = "xxxx邮箱验证" html_message = ‘<p>尊敬的用户您好!</p>‘ ‘<p>感谢您使用xxxx。</p>‘ ‘<p>您的邮箱为:%s 。请点击此链接激活您的邮箱:</p>‘ ‘<p><a href="%s">%s<a></p>‘ % (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的任务
# celery服务器的入口 from celery import Celery # 为celery使用django配置文件进行设置 import os if not os.getenv(‘DJANGO_SETTINGS_MODULE‘): os.environ[‘DJANGO_SETTINGS_MODULE‘] = ‘meiduo_mall.settings.dev‘ # 创建celery客户端实例 celery_app=Celery(‘meiduo‘) # 加载celery配置 celery_app.config_from_object(‘celery_tasks.config‘) # 自动注册异步任务:celery会自动的寻找封装异步任务的包里面的tasks.py文件 # 就是告知celery_app去哪里找异步任务 celery_app.autodiscover_tasks([‘celery_tasks.sms‘,‘celery_tasks.email‘])
启动celery:
pycharm 终端terminal进入到包含celery_tasks的目录中,此项目进入到meiduo_mall,输入命令:celery -A celery_tasks.main worker -l info 出现下图所示红圈中标注的send_verify_email,说明发送邮箱验证异步开启成功(另一个send_sms_code是之前做得发送短信的异步任务)
在users/models.py文件中的User模型类中定义生成验证邮箱链接的方法
邮箱的激活链接是用户点击时会访问的网址,我们让用户点击时进入到success_verify_email.html页面
from itsdangerous import TimedJSONWebSignatureSerializer as TJWSSerializer from django.conf import settings from . import constants def generate_verify_email_url(self): """ 生成验证邮箱的url """ serializer = TJWSSerializer(settings.SECRET_KEY, expires_in=constants.VERIFY_EMAIL_TOKEN_EXPIRES) data = {‘user_id‘: self.id, ‘email‘: self.email} token = serializer.dumps(data).decode() verify_url = ‘http://www.meiduo.site:8080/success_verify_email.html?token=‘ + token return verify_url
新建users/constants.py文件 添加邮箱验证链接有效期
# 邮箱验证链接有效期:一天 VERIFY_EMAIL_TOKEN_EXPIRES=60*60*24
验证邮箱链接
当用户点击邮箱里的链接时,进入到success_verify_email.html页面。
在该页面中,我们将请求网址中用于验证的token发送给后端接口,由后端接口判断token的有效性,如果token有效,则修改邮箱的验证状态,并将处理结果返回给前端展示给用户。
在users/views.py 中新建视图
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from users.models import User # url(r‘^emails/verification/$‘, views.VerifyEmailView.as_view()), class VerifyEmailView(APIView): """验证邮件是否是真实的邮件""" def get(self, request): # 获取token token = request.query_params.get(‘token‘) if not token: return Response({"message":‘缺少token‘}, status=status.HTTP_400_BAD_REQUEST) # 验证token,并返回user user = User.check_verify_email_token(token) if not user: return Response({"message": ‘无效的token‘}, status=status.HTTP_400_BAD_REQUEST) # 修改当前user的email_active属性的值为True user.email_active = True user.save() return Response({‘message‘:‘Ok‘})
在users/models.py文件中的User模型类中定义验证token的方法
from itsdangerous import TimedJSONWebSignatureSerializer as TJWSSerializer,BadData @staticmethod def check_verify_email_token(token): """验证token并获取user""" serializer = TJWSSerializer(settings.SECRET_KEY, expires_in=constants.VERIFY_EMAIL_TOKEN_EXPIRES) try: data = serializer.loads(token) # BadData是loads异常的祖宗 except BadData: return None else: user_id = data.get(‘user_id‘) email = data.get(‘email‘) try: user = User.objects.get(id=user_id, email=email) except User.DoesNotExist: return None else: return user
在users/urls.py文件中配置验证邮箱的路由信息
urlpatterns=[ # 验证邮箱 url(r‘^emails/verification/$‘, views.VerifyEmailView.as_view()), ]
最后测试一下就ok了
以上是关于Django发送邮件及邮件激活的主要内容,如果未能解决你的问题,请参考以下文章