美多商城QQ第三方登录和邮箱验证

  • 第三方登录, QQ登录
    # 先生成一个跳转地址
class QQAuthURLView(APIView):
      def get(self, request):
          next = request.query_params.get('state')
          if not next:
              next = '/'
          
          oauth = OAuthQQ(client_id=dev.QQ_CLIENT_ID,client_secret=dev.QQ_CLIENT_SECRET,redirect_uri=dev.QQ_REDIRECT_URI,state=next)
          login_url = oauth.get_qq_url()
          return Response({'login_url':login_url})
  • 在跳转地址先生成一个code值发送给后端, 作用是判断是否已经绑定用户了

    qq_login: function(){
    var next = this.get_query_string(‘next’) || ‘/’;
    axios.get(this.host + ‘/oauth/qq/authorization/?next=’ + next, {
    responseType: ‘json’,
    withCredentials: true
    })
    .then(response => {
    location.href = response.data.login_url;
    })

  • 后端收到code值, 生成openid, 判断OAuthQQUser表中是否有该openid

    • 如果有, 返回一个完整信息, 前端判断出传回来user_id后会直接跳转到state页面

from itsdangerous import TimedJSONWebSignatureSerializer as TJS
class QQUserView(CreateAPIView):
serializer_class = OauthSerializer
def get(self, request):
code=request.query_params.get(‘code’)
# 在这里传入state
qq=OAuthQQ(client_id=settings.QQ_CLIENT_ID,
client_secret=settings.QQ_CLIENT_SECRET,
redirect_uri=settings.QQ_REDIRECT_URI, state=’/’)
access_token=qq.get_access_token(code)
openid=qq.get_open_id(access_token)
try:
qq=OAuthQQ.objects.get(openid=openid)
except:
# 没有这个用户就要绑定操作了, 先把加密后的openid发到前端
tjs = TJS(settings.SECRET_KEY,300)
open_id = tjs.dumps({‘openid’:openid}).decode()
return Response({‘access_token’:open_id})
else:
# 返回数据要携带token值,user_id,username
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
# 用外键获取对象
user=qq.user
return Response({
‘token’: token,
‘user_id’: user.id,
‘username’: user.username
})

  • 如果没有找到, 会返回加密后的openid, 前端显示绑定界面

access_token_openid = generate_save_user_token(openid)
return Response({‘access_token’:access_token_openid})

  • 前端输入字段, 发送短信验证码后, 点击保存, 发送一个post请求. post请求作用是验证字段和保存数据.
 CreateAPIView封装了post方法, 所以修改序列化器就可以了
        class OauthSerializer(serializer.ModelSerializer):
        	sms_code = serializer.CharField(max_length=6,min_length=6,write_only=True)
        	token = serializers.CharField(read_only=True)
        	mobile = serializers.CharField(max_lenght=11)
        	access_token=serializers.CharField(write_only=True)
    	class Meta:
    		model=User
    		# 决定能在这个序列化器中来往的字段
    		fileds=('id','username','mobile','password',sms_code','token','access_token')
    		extra_kwargs={
                'username':{
                    'read_only':True
                },
                'password':{
                    'max_length':20,
                    'min_length':8,
                    'write_only':True
                },
    		}
    		
    	def validate_mobile(self,value):
    		if not re.match(r'^1[3-9]\d{9}$',value):
    			raise seriallizers.ValidationError('手机格式不正确')
    		return value
    	def validate(self,attrs):
    		conn=get_reids_connection('sms_code')
             rel_sms_code=conn.fet('sms_code_%s')%attrs['mobile']
             if not rel_sms_code:
             	raise serializers.ValidationError('短信失效')
             if attrs['sms_code'] != rel_sms_code:
             	raise serializers.ValidationError('短信错误')
             tjs=TJS(settings.SECRET_KEY,300)
             data=tjs.loads(attrs['access_token'])
             openid=data.get('oopenid')
             attrs['openid']=openid
             try:
                 user=User.objects.get(mobile=attrs['mobile'])
             except:
    			return attrs
             else:
             	if not user.check_password(attrs['password']):
                    raise serializers.ValidationError('密码错误')
              	attrs['user']=user
                return attrs
    	def create(self,attrs):
    		user=attrs.get('user')
    			if not user:
    				user=Usr.objects.create_user              											(username=attrs['username'],mobile=attrs['mobile'],                                                                        password=attrs['password'])
    			# 保存数据, 创建了一个openid和user关联的对象
                 OAuthQQUser.objects.create(user=user,openid=attrs['openid'])
                 jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
                 jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
                 payload = jwt_payload_handler(user)
                 token = jwt_encode_handler(payload)
                 user.token=token
                 return user 
  • 根据接口文档, 路由如下

urlpatterns = [
url(r’qq/authorization/ , v i e w s . O a u t h Q Q V i e w . a s v i e w ( ) ) , u r l ( r q q / u s e r / ',views.OauthQQView.as_view()), url(r'qq/user/ ’,views.QQUserView.as_view())
]

用户信息和邮箱验证

  • 用户信息, 读取前端发送的token值, 取出user对象, 然后返回前端

class UserDetailView(RetrieveAPIView):
serializer_class = UserDetailSerialzier
permission_classes = [IsAuthenticated]

      def get_object(self):
          # 所有view的子类都有一个request属性
          # 序列化返回user对象
          return self.request.user
  #序列化器如下, 决定返回的序列化数据
  class UserDetailSerializer(serializer.ModelSerializer):
  	class Meta:
  		model=User
  		fields=('id','username','mobile','email','email_active')
          extra_kwargs={
              'username':{
                  'read_only':True
              },
              'mobile':{'read_only':True},
              'email_acive':{'read_only':True}
          }
  	def
  • 用户邮箱修改, 视图和序列化器
    class UserEmailView(UpdateAPIView):
    serializer_class=UserDetailSerializer
    # 因为没有传pk值, 所以也要重写获取对象的方法
    def get_object(self):
    return self.request.user

    # view调用了序列化器完成保存更新的操作
    # 给序列化器增添update方法
    def uptate(self,instance,attrs):
        instance.email=['email']
        instance.save()
        # 加密手段
        serializer = TJWSSerializer(settings.SECRET_KEY, expires_in=300)
        data={'user_id':instance.id,'email':instance.email}
        token=serializer.dumps(data).decode()
        verify_url='http://www.meiduo.site:8080/success_verify_email.html?token=' + token
        to_email=attrs['email']
        subject="美多商城邮箱验证"
        html_message='<p>尊敬的用户您好!</p>' \
                           '<p>感谢您使用美多商城。</p>' \
                           '<p>您的邮箱为:%s 。请点击此链接激活您的邮箱:</p>' \
                           '<p><a href="%s">%s<a></p>' % (to_email, verify_url, verify_url)
        send_mial(subject,'',settings.EMAIL_FROM,[to_email],html_message=html_message)
        return instance
    
    #邮箱验证时前端发送请求,携带之前的token值, 后端取出token值,修改邮箱状态
    class UserEmailVerifyView(APIView):
        def get(self,request):
            token=request.query_params.get('token')
            tjs=TJS(setting.SECRET_KEY,300)
            data=tjs.loads(token)
            user_id=data.get('user_id')
            email=data.get('email')
            user=User.objects.get(id=user_id,email=email)
    	    user.email_active=True
            user.save()
            return Response('OK')
    

猜你喜欢

转载自blog.csdn.net/weixin_44402898/article/details/88360479