簡介
在現代的網站中,我們經常會遇到使用OAuth授權的情況,比如有一個比較小眾的網站,需要用戶登錄,但是直接讓用戶注冊就顯得非常麻煩,用戶可能因為這個原因而流失,那么該網站可以使用OAuth授權,借助於github或者其他的第三方網站的認證授權,來獲取相關的用戶信息,從而避免了用戶注冊的步驟。
當然,很可能在第三方網站上授權獲得用戶信息之后,還需要在本網站填寫一些必要的信息進行綁定,比如手機號,用戶名等等。
但是這比單純的注冊要方便太多了,也容易讓用戶接受。
今天,我們將要講解一下OAuth 2.0授權框架的構成,希望大家能夠喜歡。
OAuth的構成
在傳統的CS模式的授權系統中,如果我們想要借助第三方系統來訪問受限的資源,第三方系統需要獲取到受限資源服務器的用戶名和密碼,才能進行對資源服務器的訪問,很顯然這個是非常不安全的。
在OAuth2中,我們是怎么做的呢?
我們先來看一下OAuth2中授權的流程圖:
一般來說OAuth2中有4個角色。
resource owner: 代表的是資源的所有者,可以通過提供用戶名密碼或者其他方式來進行授權。通常來是一個人。
resource server:代表的是最終需要訪問到資源的服務器。比如github授權之后獲取到的用戶信息。
client: 用來替代resource owner來進行交互的客戶端。
authorization server: 用來進行授權的服務器,可以生成相應的Access Token。
整個流程是這樣的:
Client向resource owner發起一個授權請求,resource owner輸入相應的認證信息,將authorization grant返回給client。
client再將獲取到的authorization grant請求授權服務器,並返回access token。
client然后就可以拿着這個access token去請求resource server,最后獲取到受限資源。
refresh Token
為了安全起見,access token總是有過期時間的,那么如果token過期了怎么辦呢?
具體的辦法就是refresh Token :
我們看一下refresh token的流程圖:
前面的A,B,C,D和之前的講到的流程是一致的。
如果接下來訪問資源的時候,access token過期了,那么client會再次向認證服務發出refresh token的請求。
然后認證服務器會再次返回新的access token.
Authorization Code模式
上面我們講到的模式中,Client會保存Authorization Grant信息,並通過這個信息來去授權服務器請求Access Token。
Client直接保存Authorization Grant信息,並和授權服務器進行通信,這對client會有一定的安全限制。
如果是在web環境中,client是借助user-agent(web瀏覽器)來進行訪問的該如何處理呢?
這里向大家介紹一個Authorization Code模式。
Client通過User-Agent發起請求,並附帶跳轉鏈接。當提供了用戶的授權認證信息之后,授權服務器返回的不是token而是authorization code,拿到這個code之后,client可以通過這個code來獲取access Token或者refresh Token。
上面的授權流程圖我們可以通過一個具體的例子來說明,resource owner就是我們要訪問的資源。 Authorization Server是第三方的授權服務器,比如github的授權服務。而User-Agent就是瀏覽器。
好了,我們開始具體流程的講解:
比如用戶想獲取www.flydean.com的信息,但是需要登錄,這個時候就跳轉到github的登錄界面,我們輸入github的用戶名密碼,github會返回一個Authorization Code到我們的服務器比如 www.flydean.com/?code=code, client拿到這個code之后,會去后台請求github,去驗證這個code的合法性,如果code合法,則github會返回access token的信息,client后面就可以通過access token去github資源服務器資源了。
舉一個具體的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":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
隱式授權
在上面我們講到的幾個模式中,client都需要直接和授權服務器進行通信,從而獲取到access Token,有沒有什么方式可以不需要client和授權服務器直接通信就可以得到access token呢?
接下來我們講一下隱式授權。
上圖就是一個隱式授權的例子,和Authorization Code模式不同的是,授權服務器返回的是一個access token片段,只有這個片段,我們是無法得到access token的。
這里我們需要額外請求一次client resource服務器,服務器將會返回一個script腳本,通過這個腳本,我們對access token片段進行解析,得到最終的access token。
Resource Owner 授權密碼認證
這種模式一般出現在resource owner非常信任client的情況下。
我們先看一下流程圖:
這種模式實際上相當於用戶將密碼交給client保管,由client使用保存好的用戶名密碼向授權服務器請求資源。
Client 認證授權
這種模式下,client本身是有一定的授權范圍的,可以通過client認證授權,直接獲取到授權服務器的access token。
github的OAuth2認證流程
上面講的通用流程中,其實很多角色都可以合並的。
接下來我們具體講解一下如何使用github的OAuth2進行授權。
要使用github的OAuth2,需要首先在github中進行OAuth服務的注冊。
點擊注冊按鈕,輸入相應的信息,我們就可以完成注冊了。
這里比較重要的就是callback url,我們會通過這個callback url來傳遞授權信息。
注冊成功之后,你會得到一個Client ID和Client Secret。
github的授權步驟分為三個部分:
用戶跳轉到github的認證頁面進行授權
在這一部分中,我們需要跳轉到github的授權頁面:
https://github.com/login/oauth/authorize
上面是跳轉頁面的鏈接,這個鏈接可以接下面幾個參數:
client_id: 必須的參數,是我們上面注冊app得到的client id。
redirect_uri: 可選參數,如果不設定,則會使用注冊的時候提供的callback uri。
login:可選參數,指定具體的認證用戶名。
scope:github中權限的范圍。
state: 是一個隨機數,用來防止cross-site攻擊。
allow_signup: 是否允許在認證的時候注冊。
看一下跳轉的頁面:
用戶跳轉回要訪問的資源頁面
當用戶授權之后,就會調整到callback頁面,並帶上code:
http://www.flydean.com/login?code=b14a2dd57f11b2310f42
應用程序拿到code之后,通過調用下面的請求來獲取access token:
POST https://github.com/login/oauth/access_token
這個post請求需要帶上client_id,client_secret,code這三個必須的參數,還可以帶上兩個可選的參數redirect_uri和state。
默認情況下,我們會獲取到下面的響應信息:
access_token=e72e16c7e42f292c6912e7710c838347ae178b4a&token_type=bearer
應用程序拿到access token獲取到github用戶信息
有了access token之后,我們需要將token放到請求head中,去請求用戶信息:
Authorization: token OAUTH-TOKEN
GET https://api.github.com/user
總結
OAuth2是一個非常常用的協議,也非常的方便,主要目的就是可以使第三方服務器可以獲得授權范圍內的用戶信息。希望大家能夠喜歡。
本文作者:flydean程序那些事
本文鏈接:http://www.flydean.com/oauth-2-0-in-depth/
本文來源:flydean的博客
歡迎關注我的公眾號:「程序那些事」最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!