這一篇教程,我們一起使用Python3.6與Django2實現QQ第三方賬號登錄。
首先,如果想使用QQ第三方登錄功能,需要先在QQ互聯(https://connect.qq.com/)進行開發者認證。
認證審覈通過後,創建一個新的網站應用,並提交審覈。
網站應用審覈通過後,我們能夠的到應用的APP ID和APP Key。
另外,網站應用的回調地址建議先修改爲:http://127.0.0.1:8888/login,以方便我們編程過程中進行調試。
有了網站應用的APP ID、APP Key以及回調地址,我們就可以開始編寫代碼了。
在調用QQ的第三方登錄之前,我們先做一些準備工作。
一、創建一個Django項目,並創建應用(例如:website)。
二、進行項目設置。
示例代碼:(settings.py)
INSTALLED_APPS = [ ...省略部分代碼... 'website', ] DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'website', 'USER':'root', 'PASSWORD':'Opython.com666', 'HOST':'127.0.0.1', 'PORT':'3306', } } STATIC_ROOT=os.path.join(BASE_DIR, 'static')
三、創建數據庫與數據模型,通過模型生成數據表。
示例代碼:(models.py)
from django.db import models class User(models.Model): nickname = models.CharField('暱稱', max_length=150) openid = models.CharField('ID', max_length=128, primary_key=True) head = models.URLField('頭像') gender = models.CharField('性別', max_length=2, default='保密')
完成模型類的創建後,執行“makemigrations”和“migrate”命令進行數據表的創建。
如果執行命令時發生錯誤,可以嘗試先通過MySQL命令創建數據庫,命令中聲明字符集爲“utf8”。
mysql>CREATE DATABASE website DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
然後,再重新執行“makemigrations”和“migrate”命令。
四、添加QQ登錄圖標素材。
在應用目錄“website”下創建新的文件夾“static”,並在“static”文件夾下創建文件夾“images”,將QQ登錄的圖標存放在“images”文件夾中。
五、創建登錄頁面模板文件。
示例代碼:(login.html)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登錄</title> </head> <body> {% load static %} <!--加載靜態文件目錄--> {% if userinfo %} <!--如果存在用戶信息--> <img src="{{ userinfo.head }}">{{ userinfo.nickname }} <!--顯示頭像與暱稱--> {% else %} <!--否則--> <a href="to_login/"><img src="{% static '/images/qq.png' %}"></a> <!--顯示登錄圖標--> {% endif %} </body> </html>
上述代碼中,如果登錄之後(存在用戶信息),顯示用戶頭像和暱稱;否則(不存在用戶信息),顯示登錄圖標,可以點擊進行登錄。
六、創建視圖函數。
示例代碼:(views.py)
from django.shortcuts import render from .models import User def index(request): try: openid = request.session['openid'] # 讀取Session userinfo = User.objects.get(openid=openid) # 根據Session獲取用戶信息 return render(request, 'index.html', {'userinfo': userinfo}) except: # 如果發生異常 return render(request, 'index.html')
七、配置URL分發
示例代碼:(urls.py)
from django.contrib import admin from django.urls import path from website import views as site_view urlpatterns = [ path('',site_view.index), path('admin/', admin.site.urls), ]
完成以上準備工作之後,運行開發服務器即能夠進行登錄頁面的訪問。
接下來,我們完成QQ第三方登錄的關鍵代碼。
QQ第三方登錄需要經過以下過程:
- 網站應用獲取用戶授權碼(打開登錄頁面)
- 通過授權碼獲取訪問令牌(Access Token)
- 通過訪問令牌獲取QQ用戶的openid
- 通過openid和訪問令牌獲取用戶信息
1、網站應用獲取用戶授權碼
在模板“index.html”中我們爲QQ登錄圖片添加了鏈接“to_login/”,我們在視圖中編寫這個鏈接對應的函數。
示例代碼:(views.py)
from django.shortcuts import HttpResponseRedirect from urllib import parse import random
def to_login(request): state = str(random.randrange(100000, 999999)) # 定義一個隨機狀態碼,防止跨域僞造攻擊。 request.session['state'] = state # 將隨機狀態碼存入Session,用於授權信息返回時驗證。 client_id = '1*******9' # QQ互聯中網站應用的APP ID。 callback = parse.urlencode({'redirect_uri': 'http://127.0.0.1:8888/login'}) # 對回調地址進行編碼,用戶同意授權後將調用此鏈接。 login_url = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=%s&%s&state=%s' % ( client_id, callback, state) # 組織QQ第三方登錄鏈接 return HttpResponseRedirect(login_url) # 重定向到QQ第三方登錄授權頁面
示例代碼:(urls.py)
path('to_login/', site_view.to_login),
2、通過授權碼獲取訪問令牌(Access Token)
當用戶在QQ登錄界面中同意授權後,此時會打開回調地址並帶有授權碼的參數“code”。
此時瀏覽器地址欄顯示類似“http://127.0.0.1:8888/login/?code=C84FEE1CBE828DE5CA8BEF973E1E0FE0&state=613473”的地址。
我們需要一個視圖函數對“login/”這個URL進行處理,通過參數“code”獲取訪問令牌。
示例代碼:(urls.py)
path('login/', site_view.login),
示例代碼:(views.py)
from django.shortcuts import HttpResponse from urllib import request as req import re import json
def login(request): if request.session['state'] == request.GET['state']: # 驗證狀態碼,防止跨域僞造攻擊。 code = request.GET['code'] # 獲取用戶授權碼 client_id = '1*******9' # QQ互聯中網站應用的APP ID。 client_secret = '83b76c870************9ec664b8891' # QQ互聯中網站應用的APP Key。 callback = parse.urlencode({'redirect_uri': 'http://127.0.0.1:8888/login'}) # 對回調地址進行編碼,用戶同意授權後將調用此鏈接。 login_url = 'https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&code=%s&client_id=%s&client_secret=%s&%s' % ( code, client_id, client_secret, callback) # 組織獲取訪問令牌的鏈接 response = req.urlopen(login_url).read().decode() # 打開獲取訪問令牌的鏈接 ...接下一段代碼...
打開獲取訪問令牌的鏈接之後,獲取到的返回數據類似:
access_token=28BEF57C************622BC866E90&expires_in=7*****0&refresh_token=4D24F259****************AD146768
3、通過訪問令牌獲取QQ用戶的openid
在上一步的返回數據中,我們能看到第一部分就是訪問令牌,我們可以提取這個令牌內容,作爲獲取QQ用戶openid的參數。
示例代碼:(接上一段代碼)
access_token = re.split('&', response)[0] # 獲取訪問令牌 res = req.urlopen('https://graph.qq.com/oauth2.0/me?' + access_token).read().decode() # 打開獲取openid的鏈接 ...接下一段代碼...
打開獲取openid的鏈接之後,獲取到的返回數據類似:
callback( {“client_id”:”1*******9″,”openid”:”0D2DC10E****************66E1F801″} );
爲了獲取返回數據中的openid,我們可以單獨寫一個函數進行解析。
def parse_jsonp(jsonp_str): try: return re.search('^[^(]*?\((.*)\)[^)]*$', jsonp_str).group(1) except: raise ValueError('無效數據!')
4、通過openid和訪問令牌獲取用戶信息
此時,我們已經獲取了訪問令牌和openid,就能夠進行用戶信息的獲取了。
示例代碼:(接上一段代碼)
openid = json.loads(parse_jsonp(res))['openid'] # 從返回數據中獲取openid userinfo = req.urlopen('https://graph.qq.com/user/get_user_info?oauth_consumer_key=%s&openid=%s&%s' % ( client_id, openid, access_token)).read().decode() # 打開獲取用戶信息的鏈接 userinfo = json.loads(userinfo) # 將返回的用戶信息數據(JSON格式)讀取爲字典。 user = User.objects.get(openid=openid) # 查詢是否已存在用戶 if not user: # 如果不存在用戶 user = User() # 創建新用戶 user.openid = openid # 寫入用戶信息 user.nickname = userinfo['nickname'] # 寫入用戶信息 user.gender = userinfo['gender'] # 寫入用戶信息 user.head = userinfo['figureurl_qq_1'] # 寫入用戶信息 user.save() # 保存或更新用戶 request.session['openid'] = openid # 將已登錄的用戶openid寫入Session return render(request, 'index.html', {'userinfo': user}) else: return HttpResponse('授權失敗!')
注意:獲取的用戶信息爲JSON格式,包含了很多用戶信息內容,可以讀取爲字典然後獲取相關信息。
關於能夠獲取到的用戶信息,可以參考:http://wiki.connect.qq.com/get_user_info
另外,本教程中未對可能出現的異常進行處理(例如獲取用戶信息失敗,可以根據返回的錯誤碼進行處理),僅做正常登錄過程參考。
轉載請註明:魔力Python » Python3.6與Django2實現QQ第三方賬號登錄