Python3.6與Django2實現QQ第三方賬號登錄
這一篇教程,我們一起使用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 modelsclass 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」。
然後,再重新執行「makemigrations」和「migrate」命令。
四、添加QQ登錄圖標素材。
在應用目錄「website」下創建新的文件夾「static」,並在「static」文件夾下創建文件夾「images」,將QQ登錄的圖標存放在「images」文件夾中。
五、創建登錄頁面模板文件。
示例代碼:(login.html)
登錄{% load static %} {% if userinfo %} {{ userinfo.nickname }} {% else %} {% endif %}
上述代碼中,如果登錄之後(存在用戶信息),顯示用戶頭像和昵稱;否則(不存在用戶信息),顯示登錄圖標,可以點擊進行登錄。
六、創建視圖函數。
示例代碼:(views.py)
七、配置URL分發
示例代碼:(urls.py)
完成以上準備工作之後,運行開發伺服器即能夠進行登錄頁面的訪問。
接下來,我們完成QQ第三方登錄的關鍵代碼。
QQ第三方登錄需要經過以下過程:
網站應用獲取用戶授權碼(打開登錄頁面)
通過授權碼獲取訪問令牌(Access Token)
通過訪問令牌獲取QQ用戶的openid
通過openid和訪問令牌獲取用戶信息
1、網站應用獲取用戶授權碼
在模板「index.html」中我們為QQ登錄圖片添加了鏈接「to_login/」,我們在視圖中編寫這個鏈接對應的函數。
示例代碼:(views.py)
from django.shortcuts import HttpResponseRedirectfrom urllib import parseimport 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 HttpResponsefrom urllib import request as reqimport reimport 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進行機器學習
※Python如何實現數據可視化?
TAG:Python |