最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python編程使用DRF實(shí)現(xiàn)一次性驗(yàn)證碼OTP

 更新時(shí)間:2021年09月14日 11:29:27   作者:somenzz  
今天講一下如何用 Django REST framework[1](DRF) 來實(shí)現(xiàn) OTP,閱讀本文需要一定的 DRF 的基礎(chǔ)知識(shí),有需要的朋友可以借鑒參考下

一次性驗(yàn)證碼,英文是 One Time Password,簡(jiǎn)寫為 OTP,又稱動(dòng)態(tài)密碼或單次有效密碼,是指計(jì)算機(jī)系統(tǒng)或其他數(shù)字設(shè)備上只能使用一次的密碼,有效期為只有一次登錄會(huì)話或很短如 1 分鐘。OTP 避免了一些靜態(tài)密碼認(rèn)證相關(guān)系的缺點(diǎn),不容易受到重放攻擊,比如常見的注冊(cè)場(chǎng)景,用戶的郵箱或短信會(huì)收到一條一次性的激活鏈接,或者收到一次隨機(jī)的驗(yàn)證碼(只能使用一次),從而驗(yàn)證了郵箱或手機(jī)號(hào)的有效性。

要實(shí)現(xiàn)的功能就是:

1、驗(yàn)證碼是 6 位的數(shù)字和小寫字母的組合。

2、有效期為 5 分鐘,第二次發(fā)送驗(yàn)證碼的必須在 1 分鐘之后。

3、如果該郵箱/手機(jī)號(hào)已經(jīng)注冊(cè),則不能發(fā)送注冊(cè)驗(yàn)證碼。

具體的實(shí)現(xiàn)邏輯就是:

1、先生成滿足條件的驗(yàn)證碼。

2、發(fā)送前驗(yàn)證,是否上次發(fā)送的驗(yàn)證碼在 1 分鐘之內(nèi)?是否郵箱已經(jīng)注冊(cè)?,如果是,拒絕發(fā)送,并提示用戶,如果否,發(fā)送驗(yàn)證碼。

3、驗(yàn)證,是否是 5 分鐘之內(nèi)的驗(yàn)證碼,是否正確,如果是,則放行。否則提示用戶。

為了驗(yàn)證驗(yàn)證碼及其時(shí)效,我們需要把發(fā)送驗(yàn)證碼的時(shí)間和對(duì)應(yīng)的郵箱記錄下來,那么就需要設(shè)計(jì)一張表來存儲(chǔ)。

class VerifyCode(models.Model):
    mobile = models.CharField(max_length=11, verbose_name="手機(jī)號(hào)", blank=True)
    email = models.EmailField(verbose_name="email", blank=True)
    code = models.CharField(max_length=8, verbose_name="驗(yàn)證碼")
    add_time = models.DateTimeField(verbose_name='生成時(shí)間', auto_now_add=True)

1、生成驗(yàn)證碼

第一個(gè)邏輯非常簡(jiǎn)單,可以直接寫出代碼:

from random import choice
 def generate_code(self):
 """
 生成 6 位數(shù)驗(yàn)證碼,防止破解
 :return:
 """
 seeds = "1234567890abcdefghijklmnopqrstuvwxyz"
 random_str = []
 for i in range(6):
  random_str.append(choice(seeds))
 return "".join(random_str)

2、發(fā)送前驗(yàn)證

Django REST framework 框架的 Serializer 可以對(duì) Models 里的每一個(gè)字段進(jìn)行驗(yàn)證,我們直接在里面做填空題即可:

# serializers.py
class VerifyCodeSerializer(serializers.Serializer):
    email = serializers.EmailField(required=True)
    def validate_email(self, email):
        """
        驗(yàn)證郵箱是否合法
        """
        # 郵箱是否注冊(cè)
        if User.objects.filter(email = email).count():
            raise serializers.ValidationError('該郵箱已經(jīng)注冊(cè)')
         # 驗(yàn)證郵箱號(hào)碼合法
        if not re.match(EMAIL_REGEX, email):
            raise serializers.ValidationError('郵箱格式錯(cuò)誤')
         # 驗(yàn)證碼發(fā)送頻率
        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('請(qǐng)一分鐘后再次發(fā)送')
        return email
 

3、發(fā)送驗(yàn)證碼

發(fā)送驗(yàn)證碼,其實(shí)就是生成驗(yàn)證碼并保存的過程,借助于 Django REST framework 框架的 GenericViewSet 和 CreateModelMixin 即可實(shí)現(xiàn) view 類,代碼都有詳細(xì)的注釋,你很容易就看明白:

from rest_framework.response import Response
from rest_framework.views import status
from rest_framework import mixins, viewsets
class VerifyCodeViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin):
    """
    發(fā)送驗(yàn)證碼
    """
    permission_classes = [AllowAny] #允許所有人注冊(cè)
    serializer_class = VerifyCodeSerializer #相關(guān)的發(fā)送前驗(yàn)證邏輯
    def generate_code(self):
        """
        生成6位數(shù)驗(yàn)證碼 防止破解
        :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() 的內(nèi)容
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True) #這一步相當(dāng)于發(fā)送前驗(yàn)證      
        # 從 validated_data 中獲取 mobile
        email = serializer.validated_data["email"]
        # 隨機(jī)生成code
        code = self.generate_code()
        # 發(fā)送短信或郵件驗(yàn)證碼
        sms_status = SendVerifyCode.send_email_code(code=code, to_email_adress=email)
         if sms_status == 0:            
   # 記錄日志
 
            return Response({"msg": "郵件發(fā)送失敗"}, status=status.HTTP_400_BAD_REQUEST)
        else:
            code_record = VerifyCode(code=code, email=email)
            # 保存驗(yàn)證碼
            code_record.save()   
            return Response(
                {"msg": f"驗(yàn)證碼已經(jīng)向 {email} 發(fā)送完成"}, status=status.HTTP_201_CREATED
            )
 

SendVerifyCode.send_email_code 的實(shí)現(xiàn)如下:

#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 系統(tǒng)驗(yàn)碼', message=f'您的驗(yàn)證碼是【[code]】。如非本人操作,請(qǐng)忽略。',from_email='xxxx@163.com',recipient_list = [to_email_adress], fail_silently=False)
            return success_num
        except:
            return 0

4、注冊(cè)時(shí)驗(yàn)證

用戶注冊(cè)對(duì)于數(shù)據(jù)庫(kù)來講就是 User 類插入一條記錄,也就是 User 的 view 類的 create 操作來實(shí)現(xiàn)注冊(cè)。

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":
            # 如果是創(chuàng)建用戶,那么用 UserRegisterSerializer
            serializer_class = UserRegisterSerializer
        else:
            serializer_class = UserSerializer
        return serializer_class

這個(gè)骨架好了以后,我們現(xiàn)在來編寫 UserRegisterSerializer 類,實(shí)現(xiàn)注冊(cè)時(shí)驗(yàn)證:

# serializers.py
class UserRegisterSerializer(serializers.ModelSerializer):
    # error_message:自定義錯(cuò)誤消息提示的格式
    code = serializers.CharField(required=True, allow_blank=False, min_length=6, max_length=6, help_text='驗(yàn)證碼',
                                 error_messages={
                                     'blank': '請(qǐng)輸入驗(yàn)證碼',
                                     'required': '請(qǐng)輸入驗(yàn)證碼',
                                     'min_length': '驗(yàn)證碼格式錯(cuò)誤',
                                     'max_length': '驗(yàn)證碼格式錯(cuò)誤',
                                 }, write_only=True)
    # 利用drf中的validators驗(yàn)證username是否唯一
    username = serializers.CharField(required=True, allow_blank=False,
                                     validators=[UniqueValidator(queryset=User.objects.all(), message='用戶已經(jīng)存在')])
    email = serializers.EmailField(required=True, allow_blank=False,
                                   validators=[UniqueValidator(queryset=User.objects.all(), message='郵箱已被注冊(cè)')])
     # 對(duì)code字段單獨(dú)驗(yàn)證(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]
            # 判斷驗(yàn)證碼是否過期
            five_minutes_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)  # 獲取5分鐘之前的時(shí)間
            if last_record.add_time < five_minutes_ago:
                raise serializers.ValidationError('驗(yàn)證碼過期')
            # 判斷驗(yàn)證碼是否正確
            if last_record.code != code:
                raise serializers.ValidationError('驗(yàn)證碼錯(cuò)誤')
            # 不用將code返回到數(shù)據(jù)庫(kù)中,只是做驗(yàn)證
            # return code
        else:
            raise serializers.ValidationError('驗(yàn)證碼不存在')
    # attrs:每個(gè)字段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

至此發(fā)送驗(yàn)證碼的后端編碼已經(jīng)結(jié)束。

最后的話

一次性驗(yàn)證碼(OTP)的邏輯簡(jiǎn)單,需要思考的是如何在 DRF 的框架中填空,填在哪里?這其實(shí)需要了解 DRF 的 ModelSerializer 類和 ViewSet 類之前的關(guān)系,在調(diào)用關(guān)系上,ViewSet 類調(diào)用 ModelSerializer 來實(shí)現(xiàn)字段的驗(yàn)證和數(shù)據(jù)保存及序列化,Serializers 類不是必須的,你可以完全自己實(shí)現(xiàn)驗(yàn)證和數(shù)據(jù)保存及序列化,只不過這樣會(huì)導(dǎo)致 View 類特別臃腫,不夠優(yōu)雅,不易維護(hù)。

參考資料

[1]

Django REST framework: https://www.django-rest-framework.org

以上就是Python編程使用DRF實(shí)現(xiàn)一次性驗(yàn)證碼OTP的詳細(xì)內(nèi)容,更多關(guān)于Python編程DRF一次性驗(yàn)證碼OTP的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解python列表生成式和列表生成式器區(qū)別

    詳解python列表生成式和列表生成式器區(qū)別

    這篇文章主要介紹了python(列表生成式/器),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 利用Python代碼制作過年春聯(lián)

    利用Python代碼制作過年春聯(lián)

    這篇文章主要介紹了如何利用代碼編寫過年的春聯(lián),文中一共介紹了兩種方法,一是利用HTML+CSS+JS,二是利用Python,感興趣的可以試一試
    2022-01-01
  • 簡(jiǎn)單介紹Python中的decode()方法的使用

    簡(jiǎn)單介紹Python中的decode()方法的使用

    這篇文章主要介紹了簡(jiǎn)單介紹Python中的decode()方法的使用,是Python入門學(xué)習(xí)當(dāng)中必須掌握的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-05-05
  • python向量化與for循環(huán)耗時(shí)對(duì)比分析

    python向量化與for循環(huán)耗時(shí)對(duì)比分析

    這篇文章主要介紹了python向量化與for循環(huán)耗時(shí)對(duì)比分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • python自動(dòng)裁剪圖像代碼分享

    python自動(dòng)裁剪圖像代碼分享

    這篇文章主要介紹了python自動(dòng)裁剪圖像代碼分享,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • Python內(nèi)建類型int源碼學(xué)習(xí)

    Python內(nèi)建類型int源碼學(xué)習(xí)

    這篇文章主要為大家介紹了Python內(nèi)建類型int源碼學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Python環(huán)境Pillow( PIL )圖像處理工具使用解析

    Python環(huán)境Pillow( PIL )圖像處理工具使用解析

    這篇文章主要介紹了Python環(huán)境Pillow( PIL )圖像處理工具使用解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • python不同系統(tǒng)中打開方法

    python不同系統(tǒng)中打開方法

    在本篇文章里小編給大家分享的是一篇關(guān)于python在不同系統(tǒng)中打開的方法,有興趣的朋友們可以學(xué)習(xí)下。
    2020-06-06
  • Python底層封裝實(shí)現(xiàn)方法詳解

    Python底層封裝實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了Python底層封裝實(shí)現(xiàn)方法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • Python使用psutil對(duì)系統(tǒng)數(shù)據(jù)進(jìn)行采集監(jiān)控

    Python使用psutil對(duì)系統(tǒng)數(shù)據(jù)進(jìn)行采集監(jiān)控

    psutil庫(kù)可以實(shí)時(shí)獲取系統(tǒng)的一些信息,這樣就可以達(dá)到實(shí)時(shí)監(jiān)控系統(tǒng)的目的。本文對(duì)詳細(xì)講解了ython使用psutil對(duì)系統(tǒng)數(shù)據(jù)進(jìn)行采集監(jiān)控,感興趣的朋友可以看一看
    2021-08-08

最新評(píng)論

鞍山市| 拉孜县| 正镶白旗| 志丹县| 新宾| 高邑县| 饶阳县| 额敏县| 萝北县| 正镶白旗| 涞水县| 武威市| 贺兰县| 申扎县| 蓬安县| 虞城县| 鄂托克旗| 泾川县| 赤壁市| 赞皇县| 新田县| 西乌珠穆沁旗| 个旧市| 新蔡县| 鄯善县| 福鼎市| 涟水县| 金川县| 深州市| 明光市| 梁河县| 金坛市| 永昌县| 修文县| 大名县| 平舆县| 盐津县| 托克托县| 蓬溪县| 同心县| 安平县|