在之前的一篇文章中,我們已經介紹瞭如何爲一個應用添加對CAS協議的支持,進而使得我們的應用可以與所有基於CAS協議的單點登陸服務通訊。但是現在的單點登陸服務實際上並不全是通過實現CAS協議來完成的。例如Google就使用OAuth協議來管理它的帳戶。
相較於CAS協議,OAuth協議不僅僅可以完成對用戶憑證的驗證,更可以提供權限管理的功能。在這些權限管理功能的支持下,一個應用甚至可以訪問其它使用相同OAuth服務的應用的數據,從而完成應用間的交互。
OAuth集成示例
現在我們就來看一個通過OAuth協議來訪問其它應用資源的示例。
相信您或者您的許多朋友都已經在微信中關聯了LinkedIn帳號,從而可以顯示相應LinkedIn帳號的一些信息。要做到這一點,我們首先需要在微信的“設置”-> “通用”-> “功能”-> “LinkedIn”下找到關聯LinkedIn帳號的功能:
在點擊了關聯帳號以後,我們將跳轉到LinkedIn。此時LinkedIn會要求我們輸入LinkedIn帳號的用戶名和密碼,進而允許微信訪問LinkedIn帳號的部分信息:
再跳轉回到微信的時候,我們就可以看到微信已經能夠訪問相應的LinkedIn帳號的相關信息了:
關聯流程簡介
那微信和LinkedIn之間的關聯是如何建立的呢?答案就是OAuth協議。在本節中,我們將對OAuth協議的運行流程進行簡單地介紹。
注:我個人所做的工作是爲Web應用添加OAuth集成。爲該類型應用集成OAuth協議從流程上來說相對簡單,反過來卻無法較爲全面地展現OAuth協議的整體運行流程。因此在本節中我們假設手機中運行的微信是一個“confidential clients”,並可以“capable of interacting with the resource owner's user-agent (typically a web browser) and capable of receiving incoming requests (via redirection)”(RFC6749 – Section 4.1)。
實際上,在用戶點擊微信中的“關聯帳號”這個按鈕的時候,微信可能就開始啓動手機瀏覽器並轉向下面的地址:
https://{linkedin_oauth_url}/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=CALLBACK_URL&scope=read&state=xxx
該URL中包含了五個較爲重要的URL參數:
- client_id。表示微信在LinkedIn中所對應的應用ID
- redirect_uri。表示在得到了用戶授權後所需要返回到的地址
- scope。表示當前應用所申請的權限
- response_type。表示當前應用所請求的Authorization Grant的類型
- state。表示當前應用的狀態
一旦成功轉向了該URL,那麼手機瀏覽器將顯示LinkedIn的用戶登錄並賦予權限的頁面。如果用戶成功登陸並允許微信訪問這些信息,那麼我們的瀏覽器將會被重定向到redirect_uri所標示的地址。再該地址中還會通過URL參數code來記錄所得到的Authorization Grant:
https://{redirect_uri}?code=AUTHORIZATION_CODE
在瀏覽器重定向到{redirect_uri}之後,微信就知道用戶已經給與了它訪問當前用戶的LinkedIn信息的權限,並通過URL參數code來分析出剛從OAuth服務中得到的AUTHORIZATION_CODE。接下來,微信就會通過剛剛得到的AUTHORIZATION_CODE嘗試向下面的地址發送請求,以請求訪問資源所需要的令牌:
https://{linkedin_oauth_url}/token?client_id=CLIENT_ID&code=AUTHORIZATION_CODE&grant_type=authorization_code&redirect_uri=CALLBACK_URL
上面的請求中包含了四個URL參數:
- client_id:表示微信在LinkedIn中所對應的應用ID
- code:用來標示我們剛剛從服務端所得到的Authorization Grant
- grant_type:用來標示Authorization Grant的類型
- redirect_uri:用來標示成功獲得令牌的情況下所需要返回的URL
在應用成功地得到了訪問資源的令牌之後,LinkedIn將返回一個包含了資源訪問令牌的響應。同時瀏覽器將被重定向到redirect_uri所標示的位置。
接下來,應用就可以通過剛剛獲得的資源訪問令牌來訪問目標資源了。
總的來說,微信(Wechat)通過OAuth協議獲得用戶帳號信息的流程如下所示:
OAuth協議集成
在經過前面的示例講解之後,相信讀者們已經大概瞭解了OAuth協議的大致運行流程了。那麼我們現在就可以開始考慮集成OAuth協議了?是的。但是在這之前,我們首先要在OAuth服務上註冊應用。
不幸的是,LinkedIn似乎沒有對普通用戶公開應用註冊的接口。因此我們將以Digital Ocean來演示如何在一個OAuth服務上註冊一個應用。
首先,請在瀏覽器的地址欄中鍵入https://www.digitalocean.com/以來到Digital Ocean的主頁面,並註冊/登錄。接下來,在登入的界面中點擊上方的“API”,以進入應用管理頁面:
在該頁面中,我們需要點擊“Register New Application”來進入應用註冊頁面。而在該註冊頁面中,我們需要提供應用的一系列信息。這些信息包括:
- 應用的名稱
- 應用的地址
- 應用的重定向URL,即獲得了Authorization Code或資源訪問令牌後應用所需要重定向到的默認地址
註冊完畢以後,我們就會得到一個應用的ID以及相應的應用憑證。這一對信息用來在OAuth協議運行過程中證明應用的合法性。
現在我們就可以開始嘗試在應用中集成對OAuth協議的支持了。在OAuth協議的第一步,我們需要向OAuth服務提供者發送權限請求,以要求用戶賦予訪問信息的權限。就像流程簡介中所講的那樣,該請求的目標URL常常包含五個參數:
- client_id。表示應用在OAuth服務中註冊時所得到的應用ID
- redirect_uri。表示在應用得到了用戶授權後所需要返回到的地址
- scope。表示當前應用所申請的權限
- response_type。表示當前應用所請求的Authorization Grant的類型
- state。表示應用的當前狀態。通過該參數,應用可以恢復至特定狀態
這裏的五個參數都非常容易理解,但它們仍然有需要注意的地方。首先要說明的一點就是redirect_uri。它實際上是一個可選參數。在沒有標明該參數的情況下,OAuth服務所返回的重定向響應就將返回到我們剛剛在應用註冊時所指定的URL。只是在一般情況下,我們都會在發送權限請求的時候顯式地標明該參數。這在應用使用了負載平衡,分區域部署等解決方案的情況下可以更好地對應用的性能,服務的負載等衆多方面進行控制。
接下來要說的URL參數就是scope。很不幸地,在OAuth協議中並沒有規定該參數的取值範圍。也就是說,不同的OAuth服務所接受的scope參數的取值範圍可能並不相同。這聽起來可能令人有些沮喪。但是如果OAuth協議集成框架實現得比較好的情況下,該URL參數完全可以作爲框架的一個可配置的參數暴露給框架的使用者。
最後要說的就是response_type參數。OAuth協議是一個可以在多種場景下使用的協議,如Web應用,手機應用等。它們在不同的應用場景下面對的風險和需求都各不相同,從而產生了不同的獲得資源訪問令牌的方法。因此您需要根據應用的實際情況選擇合適的參數。而在這裏,我們選擇使用code,即Authorization Code Grant。因爲其流程最爲複雜,而且還支持資源訪問令牌的刷新。
在向OAuth服務發送了請求之後,如果瀏覽器能夠正確地顯示OAuth服務要求用戶賦予權限的頁面,那就表示對OAuth服務的第一步集成已經成功了。
在正確地輸入了用戶名和密碼,並同意應用的訪問請求後,應用將接收到一個重定向響應。在接收到該響應之後,應用將記錄URL參數code所標明的權限請求所得到的令牌,並使用state參數來恢復應用的狀態。
如果成功地得到權限令牌並恢復了應用狀態,我們就需要開始下一步工作:通過權限令牌來得到資源訪問令牌。在這一步中,我們需要像OAuth服務器發送如下形式的請求:
https://{linkedin_oauth_url}/token?client_id=CLIENT_ID&code=AUTHORIZATION_CODE&grant_type=authorization_code&redirect_uri=CALLBACK_URL
該請求中常常包含四個URL參數:
- client_id:表示應用在OAuth服務中所對應的應用ID
- code:用來標示我們剛剛從服務端所得到的權限令牌
- grant_type:用來標示Authorization Grant的類型
- redirect_uri:用來標示成功獲得資源訪問令牌的情況下所需要返回的URL
如果請求成功地得到了服務的響應,那麼我們就需要從響應中分析得到資源訪問令牌access_token以及其它的一系列信息:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "2YotnFZFEjr1zCsicMWpAA",
"token_type": "code",
"expires_in": 3600,
"refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter": "xxx"
}
在成功地從響應中解析出了資源訪問令牌以後,我們就可以嘗試着向資源服務器發送資源訪問請求了。在該請求中,我們只需要將資源訪問令牌作爲請求的Authorization頭即可。如果資源能夠成功返回,那麼表示我們對OAuth協議的集成已經基本成功了。
Refresh Token
當然,工作還沒有完全結束。在從OAuth服務器所得到的響應中還有一個較爲重要的信息:refresh_token。它用來從OAuth服務那裏再次獲得一個資源訪問令牌。這在原有的資源訪問令牌過期的情況下非常有用。
在需要通過refresh token更新資源訪問令牌的時候,我們需要向OAuth服務再次發送一個獲取資源訪問令牌的請求。只是在該請求中,我們需要將URL參數grant_type設置爲“refresh_token”,並通過URL參數refresh_token來標明之前得到的refresh_token。如果OAuth服務能夠返回一個正確的響應並且能夠通過該響應中包含的新的資源訪問令牌訪問資源服務器上的資源,那麼就表示我們已經完成了對refresh token的支持。
Reference
OAuth協議:http://tools.ietf.org/html/rfc6749
轉載請註明原文地址並標明轉載:http://www.cnblogs.com/loveis715/p/4491456.html
商業轉載請事先與我聯繫:[email protected]
注:
- 本文在講解OAuth流程時所列出的各個URL只用來作爲講解使用,而不作爲任何考證依據。一切URL格式都應以相應版本協議中所定義的URL格式爲準
- 本文在介紹微信與LinkedIn關聯的圖片來自於百度經驗
- 關於更多的關於OAuth2.0的知識,點擊這裏。