温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2021-09-14 13:35:33 来源:亿速云 阅读:177 作者:小新 栏目:开发技术

这篇文章主要为大家展示了“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.py class 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 Response from rest_framework.views import status from rest_framework import mixins, viewsets class 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-8 from django.core.mail import send_mail class 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, UserSerializer class 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.py class 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”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI