手機注冊和第三方登錄


Django rest framwork之登錄和注冊

一.手機注冊

  1.基於雲片網第三方服務(功能很多,這里只使用國內短信):

    1.1開發者認證:

 

    1.2申請簽名:

    1.3申請模板:

    1.4進入api文檔查看相關接口:

    1.5發送短信的ip地址配置(本機或服務器):加入白名單才允許發送短信

 

   2.編寫Python的短信接口:

    2.1雲片網發送驗證碼:

import json

import requests


class YunPian(object):
    def __init__(self,api_key):
        self.api_key=api_key
        self.single_send_url='https://sms.yunpian.com/v2/sms/single_send.json'
    def send_sms(self,code,mobile):
        params={
            "apikey":self.api_key,
            "mobile":mobile,
#text必須和模板中一樣
"text":"【劉勇七】您的驗證碼是{code}。如非本人操作,請忽略本短信".format(code=code) } response=requests.post(self.single_send_url,data=params) re_dic=json.loads(response.text) return re_dic # print(re_dic) if __name__=='__main__':
#這里為雲片網的APIKEY yunpian
=YunPian('d97*******0b6') yunpian.send_sms('2017','17723722825')

       2.2驗證碼及手機號序列化:

 1 .....
 2 from Vueshops.settings import REGEX_MOBILE
 3 from .models import VerifyCode
 4 class SmsSerializer(serializers.Serializer):
 5     '''
 6     注冊手機號和驗證碼序列化
 7     '''
 8     mobile = serializers.CharField(max_length=11,min_length=11)
 9 
10     def validate_mobile(self, mobile):
11         '''
12         驗證手機號碼
13         '''
14         # 驗證手機是否合法
15         if not re.match(REGEX_MOBILE, mobile):
16             raise serializers.ValidationError('手機號非法')
17         # 手機是否注冊
18         if User.objects.filter(mobile=mobile).count():
19             raise serializers.ValidationError('用戶已經存在')
20         on_minute_ago = datetime.now() - timedelta(hours=0, minutes=1, seconds=0)
21         if VerifyCode.objects.filter(add_time__gt=on_minute_ago, mobile=mobile):
22             raise serializers.ValidationError('距離上一次發送未超過60秒')
23         return mobile

 

    2.3viewset生成驗證碼及發送接口:

....
from Vueshops.settings import APIKEY
from .models import UserProfile,VerifyCode
from .serializers import SmsSerializer,UserRegSerializer,UserDetailSerializer
from utils.yunpian import YunPian
class SmsCodeViewset(mixins.CreateModelMixin,viewsets.GenericViewSet):
    '''
    雲片網發送短信驗證碼接口
    '''
    serializer_class = SmsSerializer

    def generate_code(self):
        seeds = '1234567890'
        random_str = []
        for i in range(4):
            random_str.append(random.choice(seeds))
        return ''.join(random_str)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
#如果序列化錯誤,直接拋異常,不會進入后面階段 serializer.is_valid(raise_exception
=True) mobile=serializer.validated_data['mobile'] yun_pian=YunPian(APIKEY) code=self.generate_code() ssm_status=yun_pian.send_sms(code=code,mobile=mobile) if ssm_status['code']!=1: return Response({'mobile':ssm_status["msg"]},status=status.HTTP_400_BAD_REQUEST) else: code_record=VerifyCode(code=code,mobile=mobile) code_record.save() return Response({'mobile': mobile},status=status.HTTP_201_CREATED) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

  3.注冊接口:

       3.1注冊序列化:

....
from datetime import datetime
from datetime import timedelta

from rest_framework import serializers
from django.contrib.auth import get_user_model
from rest_framework.validators import UniqueValidator

from Vueshops.settings import REGEX_MOBILE
from .models import VerifyCode

User = get_user_model()


class SmsSerializer(serializers.Serializer):
    '''
    注冊手機號和驗證碼序列化
    '''
    mobile = serializers.CharField(max_length=11,min_length=11)

    def validate_mobile(self, mobile):
        '''
        驗證手機號碼
        '''
        # 驗證手機是否合法
        if not re.match(REGEX_MOBILE, mobile):
            raise serializers.ValidationError('手機號非法')
        # 手機是否注冊
        if User.objects.filter(mobile=mobile).count():
            raise serializers.ValidationError('用戶已經存在')
        on_minute_ago = datetime.now() - timedelta(hours=0, minutes=1, seconds=0)
        if VerifyCode.objects.filter(add_time__gt=on_minute_ago, mobile=mobile):
            raise serializers.ValidationError('距離上一次發送未超過60秒')
        return mobile


class UserRegSerializer(serializers.ModelSerializer):
    '''
    用戶注冊序列化
    '''
    # write_only=True,不會拿該字段來序列化,labe標簽名,help_text:docs文檔中description
    code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4, label='驗證碼',
                                 error_messages={
                                     "blank": "請輸入驗證碼",
                                     "required": "驗證碼不能為空",
                                     "max_length": "驗證碼格式錯誤",
                                     "min_length": "驗證碼格式錯誤"
                                 },help_text='驗證碼')
    username = serializers.CharField(required=True, allow_blank=False,
                                     validators=[UniqueValidator(queryset=User.objects.all(), message='用戶已經存在')])
    #style密文,write_only=True不返回,保存為明文
    password = serializers.CharField(style={"input_type":"password"},write_only=True)
    #重載create函數,保存為密文,該方法可以實現加密密碼,還可以信號(分離性好)
    # def create(self, validated_data):
    #     user=super(UserRegSerializer,self).create(validated_data=validated_data)
    #     user.set_password(validated_data['password'])
    #     user.save()
    #     return user

    def validate_code(self, code):
        # 不用get,如果返回兩條數據以上,會拋異常
        # try:
        #   verify_codes=VerifyCode.objects.get(mobile=self.initial_data['username'])
        # except VerifyCode.DoesNotExist as e:
        #     pass
        # except VerifyCode.MultipleObjectsReturned as e:
        #     pass
        verify_codes = VerifyCode.objects.filter(mobile=self.initial_data['username']).order_by('-add_time')
        if verify_codes:
            last_verfycode = verify_codes[0]
            five_minute_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
            if five_minute_ago > last_verfycode.add_time:
                raise serializers.ValidationError('驗證碼過期')
            if code != last_verfycode.code:
                raise serializers.ValidationError('驗證碼錯誤')
        else:
            raise serializers.ValidationError('驗證碼錯誤')

    # 作用於所有字段
    def validate(self, attrs):
        attrs["mobile"] = attrs["username"]
        del attrs["code"]
        return attrs

    class Meta:
        model = User
        fields = ('username', 'code', 'mobile', 'password')

 

    3.2注冊view:

....
from rest_framework import status
from rest_framework.response import Response
from rest_framework import permissions
from rest_framework import authentication
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework_jwt.serializers import jwt_encode_handler,jwt_payload_handler
class UserViewset(mixins.CreateModelMixin,mixins.UpdateModelMixin,mixins.RetrieveModelMixin,viewsets.GenericViewSet): ''' 用戶 ''' serializer_class = UserRegSerializer queryset = User.objects.all() authentication_classes = (JSONWebTokenAuthentication,authentication.SessionAuthentication) #更新,添加用戶信息放在一起,是否登錄應該動態,注冊不用登錄IsAuthenticated,該方法不行 # permission_classes = (permissions.IsAuthenticated) def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user=self.perform_create(serializer) re_dict=serializer.data payload=jwt_payload_handler(user) re_dict['token']=jwt_encode_handler(payload) re_dict['name']=user.name if user.name else user.username headers = self.get_success_headers(serializer.data) return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers) def get_serializer_class(self): ''' 重載GenericAPIView中的get_serializer_class函數,調用不同的序列化類,如果是create, 就調用UserRegSerializer序列化,否則UserDetailSerializer序列化 :return: ''' if self.action == 'retrieve': return UserDetailSerializer elif self.action == 'create': return UserRegSerializer return UserDetailSerializer def get_permissions(self): ''' 重載APIview中的get_perimissions函數,如果是新增用戶則不用登錄,否則必須登錄 :return: ''' if self.action == 'retrieve': return [permissions.IsAuthenticated()] elif self.action == 'create': return [] return [] def get_object(self): ''' 返回當前用戶 :return: ''' return self.request.user def perform_create(self, serializer): return serializer.save()

二.第三方登錄

  1.登錄只能跳轉到第三方的登錄頁面,防止信息泄露,有微信,QQ,微博等開放平台。

  2.微博開放平台:

    2.1正式開發中,需要認證相關信息並提交審核,審核通過了才能使用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM