成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用 Django REST Framework 來實(shí)現(xiàn)一次性驗(yàn)證碼(OTP)

開發(fā) 架構(gòu)
一次性驗(yàn)證碼,英文是 One Time Password,簡(jiǎn)寫為 OTP,又稱動(dòng)態(tài)密碼或單次有效密碼,是指計(jì)算機(jī)系統(tǒng)或其他數(shù)字設(shè)備上只能使用一次的密碼,有效期為只有一次登錄會(huì)話或很短如 1 分鐘。

[[421041]]

一次性驗(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)的有效性。

今天講一下如何用 Django REST framework[1](DRF) 來實(shí)現(xiàn) OTP,閱讀本文需要一定的 DRF 的基礎(chǔ)知識(shí)。

要實(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ǔ)。

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

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

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

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

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

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

  1. # serializers.py 
  2.  
  3. class VerifyCodeSerializer(serializers.Serializer): 
  4.     email = serializers.EmailField(required=True
  5.  
  6.     def validate_email(self, email): 
  7.         ""
  8.         驗(yàn)證郵箱是否合法 
  9.         ""
  10.         # 郵箱是否注冊(cè) 
  11.         if User.objects.filter(email = email).count(): 
  12.             raise serializers.ValidationError('該郵箱已經(jīng)注冊(cè)'
  13.  
  14.         # 驗(yàn)證郵箱號(hào)碼合法 
  15.         if not re.match(EMAIL_REGEX, email): 
  16.             raise serializers.ValidationError('郵箱格式錯(cuò)誤'
  17.  
  18.         # 驗(yàn)證碼發(fā)送頻率 
  19.         one_minute_age = datetime.now() - timedelta(hours=0, minutes=1, seconds=0) 
  20.         if VerifyCode.objects.filter(add_time__gt=one_minute_age, email=email).count(): 
  21.             raise serializers.ValidationError('請(qǐng)一分鐘后再次發(fā)送'
  22.         return email 

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

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

  1. from rest_framework.response import Response 
  2. from rest_framework.views import status 
  3. from rest_framework import mixins, viewsets 
  4.  
  5.  
  6. class VerifyCodeViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin): 
  7.     ""
  8.     發(fā)送驗(yàn)證碼 
  9.     ""
  10.     permission_classes = [AllowAny] #允許所有人注冊(cè) 
  11.     serializer_class = VerifyCodeSerializer #相關(guān)的發(fā)送前驗(yàn)證邏輯 
  12.  
  13.     def generate_code(self): 
  14.         ""
  15.         生成6位數(shù)驗(yàn)證碼 防止破解 
  16.         :return
  17.         ""
  18.         seeds = "1234567890abcdefghijklmnopqrstuvwxyz" 
  19.         random_str = [] 
  20.         for i in range(6): 
  21.             random_str.append(choice(seeds)) 
  22.         return "".join(random_str) 
  23.  
  24.     def create(self, request, *args, **kwargs): 
  25.   # 自定義的 create() 的內(nèi)容 
  26.  
  27.         serializer = self.get_serializer(data=request.data) 
  28.         serializer.is_valid(raise_exception=True) #這一步相當(dāng)于發(fā)送前驗(yàn)證 
  29.  
  30.          
  31.         # 從 validated_data 中獲取 mobile 
  32.         email = serializer.validated_data["email"
  33.         # 隨機(jī)生成code 
  34.         code = self.generate_code() 
  35.  
  36.         # 發(fā)送短信或郵件驗(yàn)證碼 
  37.         sms_status = SendVerifyCode.send_email_code(code=code, to_email_adress=email) 
  38.  
  39.         if sms_status == 0:             
  40.    # 記錄日志 
  41.  
  42.             return Response({"msg""郵件發(fā)送失敗"}, status=status.HTTP_400_BAD_REQUEST) 
  43.         else
  44.             code_record = VerifyCode(code=code, email=email) 
  45.             # 保存驗(yàn)證碼 
  46.             code_record.save()    
  47.             return Response( 
  48.                 {"msg": f"驗(yàn)證碼已經(jīng)向 {email} 發(fā)送完成"}, status=status.HTTP_201_CREATED 
  49.             ) 

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

  1. #encoding=utf-8 
  2.  
  3. from django.core.mail import send_mail 
  4.  
  5. class SendVerifyCode(object): 
  6.     @staticmethod 
  7.     def send_email_code(code,to_email_adress): 
  8.         try: 
  9.             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
  10.             return success_num 
  11.         except
  12.             return 0 

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

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

  1. from .serializers import UserRegisterSerializer, UserSerializer 
  2. class UserViewSet(viewsets.ModelViewSet): 
  3.     ""
  4.     API endpoint that allows users to be viewed or edited. 
  5.     ""
  6.     serializer_class = UserSerializer 
  7.  
  8.     def get_serializer_class(self): 
  9.         if self.action == "create"
  10.             # 如果是創(chuàng)建用戶,那么用 UserRegisterSerializer 
  11.             serializer_class = UserRegisterSerializer 
  12.         else
  13.             serializer_class = UserSerializer 
  14.         return serializer_class 

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

  1. # serializers.py 
  2. class UserRegisterSerializer(serializers.ModelSerializer): 
  3.     # error_message:自定義錯(cuò)誤消息提示的格式 
  4.     code = serializers.CharField(required=True, allow_blank=False, min_length=6, max_length=6, help_text='驗(yàn)證碼'
  5.                                  error_messages={ 
  6.                                      'blank''請(qǐng)輸入驗(yàn)證碼'
  7.                                      'required''請(qǐng)輸入驗(yàn)證碼'
  8.                                      'min_length''驗(yàn)證碼格式錯(cuò)誤'
  9.                                      'max_length''驗(yàn)證碼格式錯(cuò)誤'
  10.                                  }, write_only=True
  11.  
  12.     # 利用drf中的validators驗(yàn)證username是否唯一 
  13.     username = serializers.CharField(required=True, allow_blank=False
  14.                                      validators=[UniqueValidator(queryset=User.objects.all(), message='用戶已經(jīng)存在')]) 
  15.  
  16.     email = serializers.EmailField(required=True, allow_blank=False
  17.                                    validators=[UniqueValidator(queryset=User.objects.all(), message='郵箱已被注冊(cè)')]) 
  18.  
  19.     # 對(duì)code字段單獨(dú)驗(yàn)證(validate_+字段名) 
  20.     def validate_code(self, code): 
  21.         verify_records = VerifyCode.objects.filter(email=self.initial_data['email']).order_by('-add_time'
  22.         if verify_records: 
  23.             last_record = verify_records[0] 
  24.             # 判斷驗(yàn)證碼是否過期 
  25.             five_minutes_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)  # 獲取5分鐘之前的時(shí)間 
  26.             if last_record.add_time < five_minutes_ago: 
  27.                 raise serializers.ValidationError('驗(yàn)證碼過期'
  28.             # 判斷驗(yàn)證碼是否正確 
  29.             if last_record.code != code: 
  30.                 raise serializers.ValidationError('驗(yàn)證碼錯(cuò)誤'
  31.             # 不用將code返回到數(shù)據(jù)庫(kù)中,只是做驗(yàn)證 
  32.             # return code 
  33.         else
  34.             raise serializers.ValidationError('驗(yàn)證碼不存在'
  35.  
  36.     # attrs:每個(gè)字段validate之后總的dict 
  37.     def validate(self, attrs): 
  38.         # attrs['mobile'] = attrs['username'
  39.         # 從attrs中刪除code字段 
  40.         del attrs['code'
  41.         return attrs 
  42.  
  43.     class Meta: 
  44.         model = User 
  45.         fields = ('username''email''password''code'
  46.         extra_kwargs = {'password': {'write_only'True}} 
  47.  
  48.     def create(self, validated_data): 
  49.         user = User
  50.             email=validated_data['email'], 
  51.             username=validated_data['username'
  52.         ) 
  53.         user.set_password(validated_data['password']) 
  54.         user.save() 
  55.         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ù)。 

本文轉(zhuǎn)載自微信公眾號(hào)「Python七號(hào)」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Python七號(hào)公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: Python七號(hào)
相關(guān)推薦

2013-04-17 09:16:37

2012-02-01 16:48:54

后門Putty

2014-03-06 15:16:18

安全管理linux安全

2024-02-28 08:18:13

Java日志項(xiàng)目

2024-04-03 09:00:10

2014-08-04 14:38:25

LinuxToken

2009-06-26 15:17:27

jQuery

2021-08-12 09:48:21

Webpack Loa工具Webpack

2023-09-26 07:11:15

KubernetesJob節(jié)點(diǎn)

2019-08-06 09:21:45

2015-04-09 09:08:20

2015-09-21 15:31:05

php實(shí)現(xiàn)驗(yàn)證碼

2022-10-17 00:07:55

Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)

2012-09-18 15:04:31

Office 2013微軟

2009-12-25 14:46:53

Windows 7文件關(guān)聯(lián)

2010-11-24 16:32:50

2021-07-26 09:56:19

AI 數(shù)據(jù)人工智能

2023-09-19 08:00:00

Python開發(fā)

2021-07-22 10:25:07

JS驗(yàn)證碼前端

2011-04-18 13:36:42

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 欧美日韩一区二区在线观看 | 久久一二区 | 精品综合| 久久天天躁狠狠躁夜夜躁2014 | 日韩免费视频一区二区 | 国产精品视频在线观看 | 欧美网址在线观看 | 国内自拍偷拍 | 亚洲欧美日韩一区二区 | 亚洲一区久久 | 久久国产精品久久久久久 | 操人视频在线观看 | 日韩在线不卡 | 国产精品久久福利 | 成人免费在线观看视频 | 欧美日韩中文字幕 | 国产精品1区2区 | 中文字幕一区二区三区在线乱码 | 精品在线一区 | 国外成人在线视频网站 | 国产精品久久久久久久久久妞妞 | 国产精品美女久久久久aⅴ国产馆 | 国产亚洲精品美女久久久久久久久久 | 麻豆精品久久 | 精品国产一区二区三区久久影院 | 精品欧美一区二区在线观看 | 天堂免费 | 99精品欧美一区二区三区综合在线 | 免费a大片| 观看av | 99伊人| 欧美性区 | 国产一区二区免费 | 国产区在线 | 久久精品国产一区二区电影 | 全免费a级毛片免费看视频免 | 久久久久久av | 亚洲综合国产 | 国产一级免费视频 | 国产精品视频一区二区三区四蜜臂 | 久久久看 |