千家信息网

Python编程如何使用DRF实现一次性验证码OTP

发表于:2024-10-05 作者:千家信息网编辑
千家信息网最后更新 2024年10月05日,这篇文章主要为大家展示了"Python编程如何使用DRF实现一次性验证码OTP",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"Python编程如何使用DRF
千家信息网最后更新 2024年10月05日Python编程如何使用DRF实现一次性验证码OTP

这篇文章主要为大家展示了"Python编程如何使用DRF实现一次性验证码OTP",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"Python编程如何使用DRF实现一次性验证码OTP"这篇文章吧。

一次性验证码,英文是 One Time Password,简写为 OTP,又称动态密码或单次有效密码,是指计算机系统或其他数字设备上只能使用一次的密码,有效期为只有一次登录会话或很短如 1 分钟。OTP 避免了一些静态密码认证相关系的缺点,不容易受到重放攻击,比如常见的注册场景,用户的邮箱或短信会收到一条一次性的激活链接,或者收到一次随机的验证码(只能使用一次),从而验证了邮箱或手机号的有效性。

要实现的功能就是:

1、验证码是 6 位的数字和小写字母的组合。

2、有效期为 5 分钟,第二次发送验证码的必须在 1 分钟之后。

3、如果该邮箱/手机号已经注册,则不能发送注册验证码。

具体的实现逻辑就是:

1、先生成满足条件的验证码。

2、发送前验证,是否上次发送的验证码在 1 分钟之内?是否邮箱已经注册?,如果是,拒绝发送,并提示用户,如果否,发送验证码。

3、验证,是否是 5 分钟之内的验证码,是否正确,如果是,则放行。否则提示用户。

为了验证验证码及其时效,我们需要把发送验证码的时间和对应的邮箱记录下来,那么就需要设计一张表来存储。

class VerifyCode(models.Model):    mobile = models.CharField(max_length=11, verbose_name="手机号", blank=True)    email = models.EmailField(verbose_name="email", blank=True)    code = models.CharField(max_length=8, verbose_name="验证码")    add_time = models.DateTimeField(verbose_name='生成时间', auto_now_add=True)

1、生成验证码

第一个逻辑非常简单,可以直接写出代码:

from random import choice def generate_code(self): """ 生成 6 位数验证码,防止破解 :return: """ seeds = "1234567890abcdefghijklmnopqrstuvwxyz" random_str = [] for i in range(6):  random_str.append(choice(seeds)) return "".join(random_str)

2、发送前验证

Django REST framework 框架的 Serializer 可以对 Models 里的每一个字段进行验证,我们直接在里面做填空题即可:

# serializers.pyclass VerifyCodeSerializer(serializers.Serializer):    email = serializers.EmailField(required=True)    def validate_email(self, email):        """        验证邮箱是否合法        """        # 邮箱是否注册        if User.objects.filter(email = email).count():            raise serializers.ValidationError('该邮箱已经注册')         # 验证邮箱号码合法        if not re.match(EMAIL_REGEX, email):            raise serializers.ValidationError('邮箱格式错误')         # 验证码发送频率        one_minute_age = datetime.now() - timedelta(hours=0, minutes=1, seconds=0)        if VerifyCode.objects.filter(add_time__gt=one_minute_age, email=email).count():            raise serializers.ValidationError('请一分钟后再次发送')        return email

3、发送验证码

发送验证码,其实就是生成验证码并保存的过程,借助于 Django REST framework 框架的 GenericViewSet 和 CreateModelMixin 即可实现 view 类,代码都有详细的注释,你很容易就看明白:

from rest_framework.response import Responsefrom rest_framework.views import statusfrom rest_framework import mixins, viewsetsclass VerifyCodeViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin):    """    发送验证码    """    permission_classes = [AllowAny] #允许所有人注册    serializer_class = VerifyCodeSerializer #相关的发送前验证逻辑    def generate_code(self):        """        生成6位数验证码 防止破解        :return:        """        seeds = "1234567890abcdefghijklmnopqrstuvwxyz"        random_str = []        for i in range(6):            random_str.append(choice(seeds))        return "".join(random_str)    def create(self, request, *args, **kwargs):  # 自定义的 create() 的内容        serializer = self.get_serializer(data=request.data)        serializer.is_valid(raise_exception=True) #这一步相当于发送前验证              # 从 validated_data 中获取 mobile        email = serializer.validated_data["email"]        # 随机生成code        code = self.generate_code()        # 发送短信或邮件验证码        sms_status = SendVerifyCode.send_email_code(code=code, to_email_adress=email)         if sms_status == 0:               # 记录日志             return Response({"msg": "邮件发送失败"}, status=status.HTTP_400_BAD_REQUEST)        else:            code_record = VerifyCode(code=code, email=email)            # 保存验证码            code_record.save()               return Response(                {"msg": f"验证码已经向 {email} 发送完成"}, status=status.HTTP_201_CREATED            )

SendVerifyCode.send_email_code 的实现如下:

#encoding=utf-8from django.core.mail import send_mailclass SendVerifyCode(object):    @staticmethod    def send_email_code(code,to_email_adress):        try:            success_num = send_mail(subject='xxx 系统验码', message=f'您的验证码是【[code]】。如非本人操作,请忽略。',from_email='xxxx@163.com',recipient_list = [to_email_adress], fail_silently=False)            return success_num        except:            return 0

4、注册时验证

用户注册对于数据库来讲就是 User 类插入一条记录,也就是 User 的 view 类的 create 操作来实现注册。

from .serializers import UserRegisterSerializer, UserSerializerclass UserViewSet(viewsets.ModelViewSet):    """    API endpoint that allows users to be viewed or edited.    """    serializer_class = UserSerializer     def get_serializer_class(self):        if self.action == "create":            # 如果是创建用户,那么用 UserRegisterSerializer            serializer_class = UserRegisterSerializer        else:            serializer_class = UserSerializer        return serializer_class

这个骨架好了以后,我们现在来编写 UserRegisterSerializer 类,实现注册时验证:

# serializers.pyclass UserRegisterSerializer(serializers.ModelSerializer):    # error_message:自定义错误消息提示的格式    code = serializers.CharField(required=True, allow_blank=False, min_length=6, max_length=6, help_text='验证码',                                 error_messages={                                     'blank': '请输入验证码',                                     'required': '请输入验证码',                                     'min_length': '验证码格式错误',                                     'max_length': '验证码格式错误',                                 }, write_only=True)    # 利用drf中的validators验证username是否唯一    username = serializers.CharField(required=True, allow_blank=False,                                     validators=[UniqueValidator(queryset=User.objects.all(), message='用户已经存在')])    email = serializers.EmailField(required=True, allow_blank=False,                                   validators=[UniqueValidator(queryset=User.objects.all(), message='邮箱已被注册')])     # 对code字段单独验证(validate_+字段名)    def validate_code(self, code):        verify_records = VerifyCode.objects.filter(email=self.initial_data['email']).order_by('-add_time')        if verify_records:            last_record = verify_records[0]            # 判断验证码是否过期            five_minutes_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)  # 获取5分钟之前的时间            if last_record.add_time < five_minutes_ago:                raise serializers.ValidationError('验证码过期')            # 判断验证码是否正确            if last_record.code != code:                raise serializers.ValidationError('验证码错误')            # 不用将code返回到数据库中,只是做验证            # return code        else:            raise serializers.ValidationError('验证码不存在')    # attrs:每个字段validate之后总的dict    def validate(self, attrs):        # attrs['mobile'] = attrs['username']        # 从attrs中删除code字段        del attrs['code']        return attrs    class Meta:        model = User        fields = ('username', 'email', 'password', 'code')        extra_kwargs = {'password': {'write_only': True}}    def create(self, validated_data):        user = User(            email=validated_data['email'],            username=validated_data['username']        )        user.set_password(validated_data['password'])        user.save()        return user

以上是"Python编程如何使用DRF实现一次性验证码OTP"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!

验证 邮箱 生成 用户 一次性 字段 错误 有效 内容 密码 就是 格式 编程 手机 手机号 时间 篇文章 逻辑 提示 合法 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 网络安全危害程度划分 ibm exp520存储服务器 全球新冠病毒数据库gisaid 华为软件开发源头进行标准制定 钱塘新区软件开发 软件开发公司职位结构 网站服务器安全配置 文档检索与数据库检索 数据库窗体会遇到的问题 微信语音聊天在服务器保存多久 武汉小程序软件开发 软考数据库工程师论坛 河南泰科网络技术有限公司 建筑物数据库英文怎么翻译 掌阅电子书百度网盘服务器异常 国家网络安全项目申报书 网络安全工程专业有什么课程 中学生网络安全说课课件 收费软件数据库 穿越火线更新哪个服务器最好 电脑网络安全检查重点 义马软件开发销售电话 机房管理系统连接服务器失败 数据库技术与应用的了解 深圳管理软件开发商 大唐网络技术公司招聘 国防科工局网络安全处处长 提高网络安全意识知识 全国软件开发工程师考试 大专计算机网络技术的学校
0