如果還沒有看過前一篇的朋友建議可以點
這裡看一下上一篇文章。
在上一篇中我們談到了有關於Oauth2主要的應用環節,還有為何我們需要使用Oauth2.0。
想知道RFC這個系列主要是在紀錄什麼的話可以參考
RFC
這份規格書內清楚的寫了Oauth2.0的設計準則, 如果想要清楚的知道oauth2.0底層是如何運作的可以參考看看。
值得注意的是在RFC 6749的文件內清楚的說明了Oauth2.0的角色
Oauth在傳統的架構上引入了一層授權層,用以分隔客戶端以及資源擁有者,當資源的擁有者授權客戶端(第三方應用程式)應用可以存取資源的時候,用來存放資源的伺服器會頒發一個Access Token給客戶端(第三方應用程式), 客戶端拿到Token之後就可以藉由此Token對資源做有限度的存取(並沒有拿到全部的權限)。
原文:
The OAuth 2.0 authorization framework enables a third-party application to obtain limited access to an HTTP service, either on behalf of a resource owner by orchestrating an approval interaction between the resource owner and the HTTP service, or by allowing the third-party application to obtain access on its own behalf. This specification replaces and obsoletes the OAuth 1.0 protocol described in RFC 5849.
由上面那段重點可以得知Oauth扮演的核心角色就是向第三方應用程式頒發Token,作為第三方應用跟資源網站的橋樑。
接著我們繼續往下看, RFC 6749接著介紹了4種Authorization Grant(四種獲得Token的方法)
=> authorization-code 授權碼
=> implicit 隱藏式
=> password 密碼式
=> client credentials 客戶端憑證
接著就依序介紹一下這四種獲得Token的方式個別用在哪種場景,以及需要注意的地方。
1. Authorization-Code(授權碼):
此方法是目前最為常見的一種手法,在主流的前後端分離架構上,通常採取這種方法,使得可以在後端獲得Token,所有有關於資源存取的運算都放在後端, 可以減少token暴露的機會。
先上一個謎之網站的oauth範例來看一下
以下範例都以google作為資源擁有者為準
首先前端先提供一個連結, 以上圖來說就是google的圖示。
該連結會在URL的參數上面附上一些基本訊息, 讓google知道說你現在想要進行的授權是哪種形式的,詳細的參數細節可以看一下各大網站的oauth API, 不過通常比較常見的有以下幾種。
- cliend_id: 填入第三方程式申請oauth服務時獲得的ID,主要目的是讓google知道是誰在申請。
- response_type: 參數代表目前申請token採用的是哪一種方式, 這邊填入"code",代表要申請授權碼。
- redirect_url: 參數代表如果google接受請求之後會跳轉的界面。
- scope: 參數是代表這次第三方應用申請oauth之後供存取的權限(授權範圍)。
--------------------------------------------------------------------------------------------------------------
好的,上方假設我們使用者按下了google的圖標並且輸入帳號密碼登入了google,代表使用者同意授權資料的存取權給第三方的應用程式。 接著google跳出來的視窗就會協助跳轉至redirect_url參數內所填入的URL。 並且在後面參數的部份加上授權碼(Code)。
* 授權碼本身並不能直接獲得資料的存取權, 而是後面還要藉由授權碼去獲得Access Token。
ex: https://application.com/callback?code=authorization_code << 授權碼放在url的參數中。
拿到授權碼之後就可以在後端跟google申請Access Token。
上方申請Authorization的時候不是有用到一個參數叫做client_id,其實這個是一整組的,除了client_id之後還需要搭配一個client_secret來做使用
* client_secret是後端保存的,需要小心保護不要放在前端
所以現在申請Access Token需要用到的資源有
- {client_id, client_secret}: 讓google知道目前是誰在申請資源。
- authorization_code: 是上面第一個步驟申請到的授權碼。
- grant_type: 告知google目前想要藉由授權碼來獲得Access Token。
- redirect_url: 如果申請Access Token成功的話會send json到這個URL。(google回傳給第三方應用程式的後端)
回傳的json大概會長這個樣子, refresh_token參數下方會提到。
經過上述步驟就可以把Access存放在後端而不會暴露出來,由於有多層的保護,安全性也是四種授權方法裡面最高的。
2. Implicit(隱藏式):
這個方法現在已經比較少用了,應用場景主要是在沒有後端的純前端應用上。
直接將Access Token儲存在前端, 並且因為隱藏了授權碼的使用, 所以被稱為隱藏式。
由於此方法非常的不安全, 會將Access Token暴露在前端, 所以通常只能用在安全需求低的場景, 而且對於Token的有效時間要設置的非常短, 避免有心人士利用。
通過這個方式得到授權之後,google會根據申請時候的redirect參數去跳轉。 範例如下
https://test.com/callback#token=Access_Token
值得注意的是回傳的Access_Token並不是放在Query_String中,而是放在了Fragment內, 這樣的好處是參數並不會傳回伺服器,而是僅供瀏覽器使用, 可以防止中間人攻擊的發生。
更多有關URL參數以及Fragment的細節可以參考:
URL Wiki
3. password(密碼式)
這種情境個人認為又更少使用了, 此認證方式只會出現在當使用者今天高度的信任某個第三方應用程式, RFC 6749也允許在此情況下直接將用戶google的帳號密碼告訴第三方的應用程式。
使用這種方式的時候Access_Token會直接以json的方式回傳給第三方的應用,此種方式通常較不推薦, 畢竟在網路的世界,還是要以安全為最高準則。
4. Client Credentials(憑證式)
最後一種認證方式我們稱之為憑證式,運用的場景就是今天的第三方應用並不存在前後端,而是在command底運行的應用程式,這種認證方式通常不是針對使用者,而是針對第三方應用程式量身打造的。
一般像是用在,例如我今天寫了一個應用程式需要接上youtube的API,這樣的話我就需要只用這種認證方式,讓youtube知道今天我的某個應用程式要存取youtube的資源。
我寫的應用程式存取到youtube的資源之後再給全部的使用者使用, 有點類似底下的使用者都可以共享我的應用程式所存取的資源。
Refresh Token
介紹完上方幾種認證方式可能會有人提出一個疑問, 如果今天使用者的Token過期了,我們需要重新再run一輪上面的流程嗎?
其實不用,如果細心一點的朋友可能會注意到上面介紹授權碼的時候有貼出一張範例json圖片,其中有一個參數叫做refresh_token, 當今天用戶的Access Token過期的時候,就可以直接藉由refresh_token做更新Access Token, 不需要再執行完整的認證流程。