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服务器,常用的免费服务器有:163126QQ ,先设置一个邮箱为邮件服务器,可以设置自己的邮箱为邮件服务器,下面以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(subjectmessagefrom_emailrecipient_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了

猜你喜欢

转载自www.cnblogs.com/cl-python/p/9245761.html