介紹web
OAuth協議是用來解決第三方應用程序訪問Http Service的時候的認證問題。舉個例子:某視頻網站支持用戶經過微信登錄,而後獲取用戶在微信上的圖像信息。json
在這個場景裏瀏覽器
微信充當的就是Http Service角色。安全
視頻網站就是第三方應用服務器
而視頻網站從微信獲取用戶圖像時,微信須要進行認證就是這裏的認證問題微信
用戶在微信上登錄後,產生的在視頻網站中訪問用戶微信上的圖像時所需的認證信息,就是OAuth解決認證問題的方式app
名詞定義網站
OAuth協議中定義了以下角色:url
Resource Owner: 資源的全部者,好比此處的微信用戶spa
Resource Server: 存儲資源的服務器,好比此處的微信服務器
Authorization Server: 負責對用戶驗證併產生訪問Resource Server時所須要的認證信息的服務器。
Client: 向Resource Server請求資源的應用程序。好比此處的視頻網站。(網站後臺)
User-Agent:用戶代理,好比瀏覽器
整體流程
整體的認證流程以下:
圖1
A:Client向Resource Owner請求認證信息
B:Resource Owner提供認證信息(好比:用戶名密碼)
C: 將認證信息提交給Authorization Server進行認證
D:認證經過,Authorization Server返回Access Token
E:Client經過Access Token訪問Resource Server中受保護的資源
步驟A,B中能夠是發生在Client上,也多是Client將用戶導航到Authorization Server上進行。
步驟E中,根據Access Token的類型,Resource Server多是本身驗證,也多是調用Authroization Server進行驗證。
OAuth實際上是建立了一個抽象層(Authorization Server)。
它主要負責兩件事情:驗證用戶,產生統一的用於訪問Resource Server驗證信息。
驗證的用戶的方式能夠是多種多樣(用戶名/密碼, 手機驗證碼...),所以這個抽象層將各類驗證方式統一爲此處的Access Token.這樣對Resource Server屏蔽了用戶驗證的多樣性,簡化了邏輯。
受權模式
上面流程中最重要的實際上是步驟ABCD,經過收集Resource Owner的認證信息,產生一個Access Token.這個過程稱做Resource Owner對Client的受權。OAuth定義了四種受權模式:
受權碼模式
簡化模式
密碼模式
Clent驗證模式
受權碼模式
流程圖以下
受權碼模式是四種模式中最嚴謹的一種。Client首先要到Authorization Server上註冊,獲取到一個Id.(這樣只有被容許的Client才能經過OAuth進行驗證,增強了安全性)
上面步驟中:
A Client將用戶導航到Authorization Server的Authorize endpoint,同時帶上clientId(這樣Authorization Server能夠對Client進行驗證),認證結束後的跳轉url.
Http請求以下:
GET https://sample.com/authroize?response_type=code&clientId=xxx&redirect_uri=https://www.client.com/oauthcallback.aspx
B 用戶在Authroization Server的頁面上輸入本身的驗證信息。
C Authorization Server經過導航用戶到步驟A中指定的url,並將受權碼以query string的形式提供。
Http Response信息以下:
HTTP/1.1 302 Found Location: https://www.client.com/oauthcallback.aspx?code=xxx
D Client獲得受權碼後,調用Authorization Sever的接口(同時傳入受權碼和跳轉URL,Authroization Server會對二者進行配對驗證,以確保安全)
Http請求以下:
POST www.example.com/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=xxx &redirect_uri=https://www.client.com/oauthcallback.aspx
E Authorization Server返回Access Token給Client,Client存儲下來,在後續請求中使用。
Response以下:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", "example_parameter":"example_value" }
在這個過程當中,
1. Client沒有接觸到用戶的驗證信息(用戶名/密碼)
2. user-agent沒有接觸到Access Token。
3. 將受權碼與跳轉Url配對驗證
這些都加強了整個過程的安全性。
簡化模式
簡化模式,是受權碼模式的簡化版。流程圖以下:
這裏和受權碼模式的區別是:
1. 在步驟A中,直接請求的時token而不是code
GET /authorize?response_type=token&client_id=s6BhdRkqt3&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 Host: www.example.com
2. 在步驟C中,Authorization Server直接在跳轉url中附帶上了access token,跳過了受權碼這個環節。可是access token並不是以query string的形式表示,而是以fragment(即url中的hash部分)
Http Response:
HTTP/1.1 302 Found Location: http://client.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&token_type=example&expires_in=3600
3. 根據http協議的定義,redirect時,fragment不會傳到web服務器,所以client要想獲得access token,必須在跳轉url的response中返回一段js腳原本在瀏覽器中讀到access token而後發送給client.(不太明白,OAuth中爲何要將access token放到hash中,而不是query string中)
密碼模式
流程圖以下:
密碼模式中,Resource Owner直接在client的頁面上輸入認證信息。而後經過client來獲取到access token.整個過程當中client不能存儲Resource Owner輸入的認證信息。可是協議上沒辦法強制,只能依靠對client的信任了。所以這對Resource Owner來講是不那麼安全的一種方式。
步驟B的請求以下:
POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded grant_type=password&username=johndoe&password=A3ddj3w
步驟C的Response以下:
HTTP/1.1 200 OK Content-Type: application/json;charset=UTF-8 Cache-Control: no-store Pragma: no-cache { "access_token":"2YotnFZFEjr1zCsicMWpAA", "token_type":"example", "expires_in":3600, "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA" }
Client驗證模式
流程圖以下:
其實這中方式應該不算是OAuth的適用場景裏面的。這種模式下是用Client自身在Authorization Server上的認證信息來獲取access token.也就是說把client當成一個resource owner,那麼就和具體的使用client用戶無關了。
擴展模式
採用什麼方式獲取到access token是經過token請求中的grant_type來肯定的。所以Authorization Server能夠經過這個字段來擴展更多的獲取access token的方式。
刷新Access Token
經過上述四種模式得到access token的時候,咱們同時能得到一個refresh token。access token是有有效期的(e.g. 30分鐘)。過了有效期後再使用就會報錯。這個時候能夠適用refresh token去找Authorization Server從新獲取access token,這個過程不須要Resource Owner的參與,屬於靜默執行。
具體請求以下:
POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
驗證Access Token
access token最後是發送給Resource Server的,因此Resource Server會對access token進行驗證。而具體的驗證方法取決與token的類型。
1. 若是token是一個不包含特定信息的字符串。Resource Server只能將這個token交給Authorization Server去解析拿到用戶信息了。
2. 若是token是一個包含特定用戶信息的字符串(e.g. jwt)。Resource Server則能夠自行解析token拿到用戶信息。
Authorization Server與Resource Server
Authorization Server和Resource Server能夠是在同一臺服務器上。也能夠是在不一樣的服務器上。
1. 在同一服務器上
這種狀況下第三方應用和HTTP Service實際上是同一個應用,也就是任意的http應用自身的用戶驗證均可以應用OAuth協議。這種狀況下,Authorization Server是應用的一個模塊。
2. 在不一樣服務器上
這種狀況的適用場景就比較多了。Authorization Server能夠對應多個Resource Server,從而全部的Resource Server均可以把Authorization server 做爲用戶認證信息提供者。SSO,OPEN ID均可以用這種場景。
參考:RFC6749
CS模式應用採用OAuth
前面討論的都是BS的Web應用。CS模式的應用(通訊協議爲Http)也是能夠採用OAuth協議的。
以常見的app開發爲例:
app的後臺服務其實就是resource server,咱們能夠把authorization server單獨部署或者和resource server一塊兒部署,或者是後臺服務的一個模塊。可是因爲app是本身開發的產品,屬於可信任的client。所以能夠採用密碼模式。其餘模式涉及url跳轉,獨立的驗證頁面等有點太複雜了。
不過若是app的後臺要做爲一個開放平臺,供別的app調用,就須要支持其餘模式了。由於跳轉是發生在瀏覽器裏的,所以這種狀況下app的實現也會複雜點。