OAuth與第三方登錄API

轉自IT小站

正好正在寫博客的登錄模塊,開始考慮要不要自己弄一套用戶系統,但是後來想了很久,還是決定不弄了,因為博客的用戶系統作用其實不是很大,其功能主要是為評論系統服務的,相對的,如果是社交網站,用戶的主頁與交流等功能就很重要了。在這種需求下,使用第三方登錄來作為博客的用戶體系還是比較合適的。這篇文章將詳細介紹如何使用基於OAuth協議的第三方登錄API。

什麼是 OAuth?

先來看一下Wikipedia是怎麼說的吧。

OAuth is an open standardfor access delegation, commonly used as a way for Internet users to grant websites or applications access to their information on other websites but without giving them the passwords.

說的是 OAuth 是一個開放的訪問授權標準,用戶能通過這個協議准許第三方網站或應用訪問他們在另一個網站儲存的私密資料,在這個過程中,用戶只需在儲存資料的網站中驗證自己,而無需將密碼提供給第三方網站。

OAuth 2.0協議是現在用的最多的訪問授權標準,它雖然與OAuth 1.0同出一門,但是OAuth 2.0並不兼容OAuth 1.0,所以這裡主要介紹OAuth 2.0協議。

OAuth 2.0協議的認證過程

OAuth 2.0協議涉及到了三個角色:

  • 服務提供方:即用戶資料的存儲方,比如GitHub、QQ等
  • 客戶端:即需要使用提供方資料的網站或者應用,比如我的博客
  • 用戶:將資料存放在提供方的受保護的資料擁有者,比如GitHub用戶、QQ用戶

OAuth 2.0協議的認證和授權過程如下:

  1. 客戶端向服務提供方請求一個客戶端ID(Client ID)和客戶端秘鑰(Client Secret),兩者是用於服務提供方驗證客戶端身份的,如果服務提供方允許,則客戶端即可獲得第三方登錄的許可權(通常在各大服務提供方的開發者頁面,如QQ開放平台,GitHub Developer,QQ等平台的請求相對麻煩)
  2. 用戶在客戶端使用第三方登錄功能
  3. 客戶端引導用戶跳轉到服務提供方的授權頁面請求用戶授權(如你們常見的QQ登錄授權頁面)
  4. 用戶在授權頁面使用其登錄信息登錄服務提供方並且授權客戶端使用Ta的信息(比如你們常見的QQ空間詢問是否允許XX網站使用你的XX資料)
  5. 服務提供方返回一個授權碼(Code),並且將用戶重新引導的客戶端的後台(這是一個回調網站,是可以自己設置的,自己寫一個Http響應,並且將這個Http響應的地址填到API的回調地址中)
  6. 客戶端後台使用授權碼(Code)和客戶端ID(Client ID)、客戶端秘鑰(Client Secret)等參數一同向服務提供商請求一個訪問令牌(Access Token)
  7. 服務提供商返回訪問令牌(Access Token),客戶端使用這個訪問令牌再次調用服務提供商的API即可獲取到用戶的信息

實戰

因為我的博客是使用Django(Python3)寫的,所以這裡的例子就使用Django(Python3)來操作,服務提供方的話,使用GitHub舉例,其他的平台可能大同小異,只不過GitHub想要申請客戶端身份的話最簡單。我們可以一邊看著GitHub的API一邊操作:GitHub開發者API-OAuth App

第一步,當然是在GitHub上申請一個OAuth Apps,也就是申請扮演客戶端角色:

打開網址 github.com/settings/dev ,依次選擇OAuth Apps -> New OAuth App,前幾個可以隨意填寫,最為重要的是Authorization callback URL一欄,這一條要填寫你自己為第三方登錄這一過程的Http響應地址,你可以先佔一個坑,反正後面也能改,我們也可以在Http響應(在Java Web中即Servlet,在Django中即view函數)寫完之後再填寫這一欄。

完成填寫之後,打開你剛剛新建的OAuth App,即可看到你成功申請了一個客戶端身份,在這個頁面中你即可看到之前說的Client ID 和 Client Secret,用這倆即可向服務提供商說明你客戶端的身份。

接著把你登錄頁面中的第三方認證入口的鏈接(即我們常見的使用QQ登錄、使用GitHub登錄按鈕)設置為API中說的用戶授權頁面( github.com/login/oauth/ ),同時還要按照API中的要求使用?key1=value1&key2=value2的形式拼湊成GET參數傳遞給這個URL。API中要求的必須欄位是Client ID,那麼最終的鏈接應該是上面說的用戶授權頁面URL加上?client_id=XXXXXXXXX。

如果鏈接無誤的話,用戶點擊鏈接之後應該能夠成功跳轉到GitHub的授權頁面,GitHub會詢問你是否要授權客戶端使用你的資料,你可以用這一個辦法驗證上一步是否正確。當用戶同意授權之後,GitHub會跳轉到你之前填的那個Authorization callback URL去,並且在GET參數中帶上一個code,那麼接下來,就是伺服器後台的事情了。

我們在之前已經為Authorization callback URL佔了一個坑了,比如我的是 kindemh.cn/login/github ,這個地址是你的伺服器用於處理第三方登錄的Http響應(Java Web是Servlet,Django是view函數)的地址,你之前填上去了也能改,接下來我們開始寫對應的view函數。

首先在url.py中填寫這個新增的url

# Blog/main/urls.pyurlpatterns = [ ... # github登錄 # 你的 Authorization callback URL 需要填寫的地址 url(r^login/github$, views.login_github, name=login_github)]

然後在views.py中新寫一個view函數,用於處理GitHub登錄

# Blog/main/views.py...# github 登錄回調def login_github(request): # 獲取 code code = request.GET.get(code) # 準備POST參數用於交換 access_token,即上面說的獲取訪問令牌,這裡要用到 client_id 、client secret 和 code data = bytes(urllib.parse.urlencode({ client_id: github_client_id, client_secret: github_client_secret, code: code }), encoding=utf8) # 發送Http請求用於交換 access_token response = urllib.request.urlopen(https://github.com/login/oauth/access_token, data=data) # 提取 access_token access_token = str(response.read(), encoding=utf-8).split(&)[0].split(=)[1] # 使用 access_token 獲取用戶信息 response = urllib.request.urlopen(https://api.github.com/user?access_token= + access_token) # 解碼成Python對象 user_info = json.loads(response.read().decode(utf-8)) # TODO 接下來對你的資料庫進行需要的操作,並且將用戶登錄信息存入 session,並且在最後重定向到登錄之前的頁面

在這個響應中,按照OAuth 2.0協議的步驟和GitHub的API寫了,注釋很清楚,很容易明白,這裡要注意的是在GitHub訪問的第二步(API中的step II),請求的方式是POST,大家一定要注意,很多人出問題都是在這裡。最後的TODO中,大家可以根據需求對自己的資料庫進行操作,也可以在session中保存用戶登錄信息,最後再重定向以完成第三方登錄。

這樣一來,第三方登錄就完全完成了,其實也不難,如果還是有失誤,請從上面開始認真按照步驟執行,還有問題請在評論上指出,我將會積極回復(T-T博客上的評論功能還沒做,等我做好了再指出吧)。

推薦閱讀:

從事網頁前端開發工作的人員英語發音都那麼奇怪嗎?
作為一名前端開發人員,有哪些值得一讀的js代碼?
CSS如何實現這種背景效果?
如何評價Github的新版黑色Header?
想深入了解 HTTP 協議,有哪些值得推薦的書籍?

TAG:Web开发 | Django框架 | Python |