【愚公系列】2022年01月 Django商城項(xiàng)目13-登錄界面-QQ登錄功能實(shí)現(xiàn)
前言
1.QQ互聯(lián)開(kāi)發(fā)者申請(qǐng)
若想實(shí)現(xiàn)QQ登錄,需要成為QQ互聯(lián)的開(kāi)發(fā)者,審核通過(guò)才可實(shí)現(xiàn)
相關(guān)連接:https://connect.qq.com/
第一步:首先使用qq登錄
第二步:注冊(cè)個(gè)人應(yīng)用
注冊(cè)成功后如下
2.QQ互聯(lián)應(yīng)用申請(qǐng)
成為QQ互聯(lián)開(kāi)發(fā)者后,還需創(chuàng)建應(yīng)用,即獲取本項(xiàng)目對(duì)應(yīng)與QQ互聯(lián)的應(yīng)用ID。
相關(guān)連接:https://connect.qq.com/manage.html#/appcreate/web
3.網(wǎng)站對(duì)接QQ登錄
QQ互聯(lián)提供有開(kāi)發(fā)文檔,幫助開(kāi)發(fā)者實(shí)現(xiàn)QQ登錄。
相關(guān)連接:http://wiki.connect.qq.com/%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C_oauth2-0
一、django實(shí)際對(duì)接流程
1.創(chuàng)建抽象模型類
from django.db import models class BaseModel(models.Model): """為模型類補(bǔ)充字段""" create_time = models.DateTimeField(auto_now_add=True, verbose_name="創(chuàng)建時(shí)間") update_time = models.DateTimeField(auto_now=True, verbose_name="更新時(shí)間") class Meta: abstract = True # 說(shuō)明是抽象模型類, 用于繼承使用,數(shù)據(jù)庫(kù)遷移時(shí)不會(huì)創(chuàng)建BaseModel的表
2.創(chuàng)建QQ用戶模型類
from django.db import models from utils.models import BaseModel class OAuthQQUser(BaseModel): """QQ登錄用戶數(shù)據(jù)""" # ForeignKey 我們使用了 其他子應(yīng)用的模型 # 我們采用 '子應(yīng)用名.模型類名' user = models.ForeignKey('users.User', on_delete=models.CASCADE, verbose_name='用戶') openid = models.CharField(max_length=64, verbose_name='openid', db_index=True) class Meta: db_table = 'tb_oauth_qq' verbose_name = 'QQ登錄用戶數(shù)據(jù)' verbose_name_plural = verbose_name
3.注冊(cè)應(yīng)用
# Application references # https://docs.djangoproject.com/en/2.1/ref/settings/#std:setting-INSTALLED_APPS INSTALLED_APPS = [ 'app', # Add your apps here to enable them 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app.users', 'app.oauth', ]
4.配置QQ登錄信息
# QQ登陸相關(guān)的 QQ_CLIENT_ID = '填寫(xiě)自己的' QQ_CLIENT_SECRET = '填寫(xiě)自己的' QQ_REDIRECT_URI = '填寫(xiě)自己的'
5.登錄返回的URL地址和回調(diào)信息
from django.shortcuts import render from QQLoginTool.QQtool import OAuthQQ from DJ_MeiDuo import settings from django import http from django.views import View # Create your views here. class OauthQQURLView(View): def get(self,request): #1.創(chuàng)建實(shí)例對(duì)象 state = 'test' qqoauth = OAuthQQ( client_secret=settings.QQ_CLIENT_SECRET, client_id=settings.QQ_CLIENT_ID, redirect_uri=settings.QQ_REDIRECT_URI, state=state ) #2.調(diào)用方法 login_url = qqoauth.get_qq_url() return http.JsonResponse({'login_url':login_url}) class OauthQQUserView(View): def get(self,request): # 1.獲取code code = request.GET.get('code') if code is None: return render(request,'oauth_callback.html',context={'errmsg':'沒(méi)有獲取到指定參數(shù)'}) # 2. 通過(guò)讀取文檔將code轉(zhuǎn)換為token qqoauth = OAuthQQ( client_secret=settings.QQ_CLIENT_SECRET, client_id=settings.QQ_CLIENT_ID, redirect_uri=settings.QQ_REDIRECT_URI ) token = qqoauth.get_access_token(code) #3.通過(guò)token換取openid openid = qqoauth.get_open_id(token) # 4. 我們需要根據(jù) openid 進(jìn)行數(shù)據(jù)的查詢 try: qquser = OAuthQQUser.objects.get(openid=openid) except OAuthQQUser.DoesNotExist: # 如果沒(méi)有同樣的openid,則說(shuō)明用戶沒(méi)有綁定過(guò) # 對(duì)openid進(jìn)行一個(gè)加密的處理 openid_access_token = generate_access_token(openid) return render(request,'oauth_callback.html',context={'openid_access_token':openid_access_token}) else: # 如果有同樣的openid,則說(shuō)明用戶綁定過(guò) # 則直接登陸 response = redirect(reverse('contents:index')) #1. 設(shè)置登陸狀態(tài) login(request,qquser.user) #2.設(shè)置cookie信息 response.set_cookie('username',qquser.user.username,max_age=14*24*3600) return response # return render(request,'oauth_callback.html') def post(self,request): # 1.先接收數(shù)據(jù) data = request.POST # 2.獲取數(shù)據(jù) mobile = data.get('mobile') password = data.get('pwd') sms_code = data.get('sms_code') access_token = data.get('access_token') # 3.驗(yàn)證數(shù)據(jù) # 省略 # 4.access_token( 加密之后的openid)解密 openid = check_access_token(access_token) # 5.根據(jù)手機(jī)號(hào)進(jìn)行用戶信息的判斷 try: user = User.objects.get(mobile=mobile) except User.DoesNotExist: # 如果此手機(jī)號(hào)之前沒(méi)有注冊(cè)過(guò),則重新創(chuàng)建用戶 user = User.objects.create_user( username=mobile, password=password, mobile=mobile ) else: # 如果此手機(jī)號(hào)之前注冊(cè)過(guò),綁定前要驗(yàn)證密碼 if not user.check_password(password): return http.HttpResponseBadRequest('密碼錯(cuò)誤') # 則和用戶進(jìn)行綁定, qquser = OAuthQQUser.objects.create( user=user, openid=openid ) # 6.設(shè)置登陸的狀態(tài) login(request,user) # 7.設(shè)置cookie信息 response = redirect(reverse('contents:index')) response.set_cookie('username',user.username,max_age=14*24*3600) # 8.跳轉(zhuǎn)指定頁(yè)面 return response
加解密方法的封裝
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer from app.oauth.constants import OPENID_TOKEN_EXPIRE_TIME from DJ_MeiDuo import settings def generate_access_token(openid): #1. 創(chuàng)建實(shí)例對(duì)象 s = Serializer(secret_key=settings.SECRET_KEY,expires_in=OPENID_TOKEN_EXPIRE_TIME) #2.組織數(shù)據(jù) data = { 'openid':openid } #3.加密處理 token = s.dumps(data) #4. 返回 return token.decode() def check_access_token(token): #1.創(chuàng)建實(shí)例對(duì)象 s = Serializer(secret_key=settings.SECRET_KEY, expires_in=OPENID_TOKEN_EXPIRE_TIME) #2. 解密數(shù)據(jù) result = s.loads(token) # script = {'openid':'xxxx'} #3.返回?cái)?shù)據(jù) return result['openid']
6.回調(diào)頁(yè)面邏輯功能實(shí)現(xiàn)