3、 resource owner password credentials(密碼模式)
一、什么是OAuth
所謂的OAuth(Open Authorization)本質上就是一張開放的協議,OAuth協議為用戶資源的授權提供了一個安全的、開放而又簡易的標准。 與以往的授權方式不同該授權不會使第三方觸及到用戶的賬戶信息,即第三方無需使用用戶名密碼就可以申請該用戶資源的授權,因此OAuth是安全的。這是來自百度百科對OAuth的解釋。
而OAuth2.0呢,故名思義就是OAuth的下一個版本,同時它也是授權領域的行業標准協議,OAuth2.0不支持向后兼容,即不支持OAuth1.0,徹底廢止了OAuth1.0協議,OAuth2.0致力於使客戶端開發者通過更簡單的流程為Web應用、桌面應用以及手機客戶端等設備進行授權。2012年10月,OAuth2.0協議正式發布為RFC6749。目前各大開放平台,如騰訊、新浪、百度等等也都是以OAuth2.0協議作為支撐。
二、什么場景下會用到OAuth授權
目前我們大多數的應用場景,也是我們最熟悉的使用環境就是使用第三方登錄,如:微博,QQ,微信,豆瓣等社交平台登錄,互聯網發展到今天,我們也都習慣了這種登錄方式,最大的好處就是便捷,簡化了我們一系列的注冊流程,還有一大堆帳號密碼記不住的困擾,當你碰到一個不支持第三方登錄的網站或者應用的時候,第一感覺就是厭惡,一頓噴。人永遠離不開社交,所以通過社交平台去登錄其他的平台,無疑是最受大家歡迎的方式了。
就拿CSDN為例,CSDN是支持第三方平台登錄的,截圖如下:
若用戶想使用QQ登錄,那么在傳統的認證模式中,客戶端(CSDN)請求訪問服務器上受限的資源(QQ),需要通過資源所有者(用戶的QQ賬戶)的憑證在服務器上進行認證。為了支持第三方應用程序(對於QQ來說,CSDN是第三方應用程序,是CSDN去請求訪問QQ的資源)訪問受限資源,資源所有者需要向第三方應用共享其憑證(如用戶QQ的帳號和密碼)。那這樣就會造成以下幾個問題:
-
第三方應用(CSDN)為了以后繼續使用,那么會存儲資源所有者的憑證,如密碼;
-
服務端需要支持密碼認證,盡管密碼認證不安全;
-
第三方應用若想訪問資源所有者的其他資源,資源所有者無法對其進行限制;
-
資源所有者無法收回第三方的訪問權限,除非用戶主動修改密碼;
-
如果此時第三方的數據泄漏,那也會導致資源所有者其他數據的泄漏,造成重大損失。
若此時,CSDN知道了用戶的QQ密碼,那CSDN可以任意去訪問該用戶的所有信息,而QQ無法去限制它的訪問,這不管是對QQ還是用戶本身都會是一件可怕的事,作為使用者,你永遠都無法知道應用都干了些什么。由此OAuth2.0的出現,就是為了解決這樣的問題。
三、OAuth 2.0中的4個成員
在OAuth2.0中有4個成員,Resource Owner、Resource Server、Client、Authorization Server,如圖所示:
在上面4個成員中,授權服務器可能與資源服務器在同一台服務器。
四、OAuth 2.0授權流程
流程如下,圖片來自RFC6749:
流程解析:
-
用戶打開客戶端,客戶端要求向資源所有者(即用戶)給予授權;
-
用戶同意授權;
-
客戶端得知用戶同意授權后,向授權服務器獲取授權;
-
授權服務器給予客戶端授權,並將授權碼(Access Token);
-
客戶端攜帶授權碼去請求資源服務器;
-
資源服務器將受限的資源開放給客戶端。
五、OAuth 2.0授權模式
授權許可是表示客戶用來獲取訪問令牌的資源所有者授權的憑證。此規范協議規定了4種授權類型:
-
authorization code(授權碼模式)
-
implicit(簡化模式)
-
resource owner password credentials(密碼模式)
-
client credentials(客戶端模式)
下面詳細說明各種授權模式的具體流程:
1、authorization code(授權碼模式)
授權代碼授權類型用於獲取訪問令牌和刷新令牌,並針對機密客戶端進行優化。它是一個基於重定向的流程,因此客戶端必須能夠與資源所有者的用戶代理(通常是Web瀏覽器)並且能夠從授權服務器接收傳入請求(通過重定向)。授權碼模式是功能最完整、流程最嚴密的授權模式,它的特點就是通過客戶端的后台服務器,與"服務提供商"的授權服務器進行互動。授權流程如下:
流程解析:
-
客戶端通過用戶代理,重定向請求授權服務器,所需參數:客戶端標識及重定向URL;
-
用戶選擇是否給予客戶端授權;
-
授權服務器給予客戶端一個認證授權碼,並跳轉到指定的URI;
-
客戶端使用該授權碼,重定向到授權服務器,獲取令牌;
-
授權服務器校驗該授權碼以及重定向的URI后,向客戶端發送令牌或者更新令牌。
以上均個人解釋,簡化了RFC6749官方文檔說明,大致意思是一樣的。注意的一點是,在用戶同意授權后,授權服務器並未直接將令牌發送給客戶端,而是先向客戶端發送了一個授權碼,authorization code,然后再攜帶該授權碼,再一次請求授權服務器,校驗無誤后,再發送令牌(access token),這一步是在后台自動完成的,這樣也使OAuth授權更加安全。
在該授權流程中,我們所需的幾個參數,官方文檔中要求指定的參數如下:
-
response_type 必選項 表示的是要求指定的授權類型,此處必須設置為:code
-
client_id 必選項 客戶端的唯一標識
-
redirect_uri 可選項 重定向的URI
-
scope 可選項 授權的管道
-
state 建議項 表示客戶端狀態,授權服務器會將該狀態原值返回
看完該流程以及所需的參數后,我們結合實際情況,還是上面提到的例子,以CSDN使用QQ登錄為例,看一下該過程:
(A步驟)點擊QQ登錄,跳轉到QQ帳號安全登錄界面,即騰訊的互聯平台,我們可以直接拿到此時CSDN要請求的地址:
https://graph.qq.com/oauth2.0/show?which=Login&display=pc&
response_type=code&
client_id=100270989&
redirect_uri=https://passport.csdn.net/account/login?oauth_provider=QQProvider&
state=test
這樣我們可以很清楚的看到在上面的URL中,發起了一個get請求,他的授權類型為code 授權碼模式,以及client_id,redirect_uri,state等信息,而此時頁面也跳轉到了用戶代理的頁面,讓用戶去決定是否要同意授權 :
(C步驟)當用戶輸入用戶名密碼后點擊授權並登錄,服務器會先驗證你輸入的是否正確,如果正確,頁面就會跳轉到redirect_uri的地址中,而在這個過程中發生的變化是這樣的,我們繼續查看這時的URL地址:
https://passport.csdn.net/account/login?oauth_provider=QQProvider&
code=D185F3ED93E4F1B3C5F557E6112C7A9B&
state=test
(D步驟)我們可以看到授權並登錄后它重定向到了我們指定的地址,而且還給予了一個code授權碼,另外state狀態還是在請求登錄時的狀態,在下一個步驟中,是客戶端向授權服務器申請令牌,包含以下參數:
-
grant_type 表示授權模式,此處固定為authorization_code,必選
-
code 表示上一步獲取到的授權碼,必選
-
redirect_uri 表示重定向URI,必選
-
client_id 表示客戶端ID,必選
在使用騰訊開放平台時,它會要求有一個client_secrect,是對應你客戶端ID的一個私鑰,它也是在客戶端注冊時產生的,所以在使用QQ登錄獲取令牌時,也必須指定該選項:client_secret,具體的可以看騰訊的開發文檔。那么實際上申請令牌的這個過程我們是看不到的,返回authorization code 后,我們會看到我們的客戶端此時已經登錄成功了。例如:
POST /token HTTP/1.1
Host: graph.qq.com/oauth2.0/token
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb&client_secret=fdhsjfdsj32jjfhjdk
(E步驟)若以上返回成功,那么在E步驟中會返回如下信息:
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"
}
里面包含了我們所需要的令牌access token以及有效期等信息。實際上在我們實際應用過程中,我們不止是到這里就結束了,我們會使用access token令牌再去請求資源服務器,獲取可以被調用的資源,以及一些其他的操作。
2、implicit(簡化模式)
簡化模式用於獲取訪問令牌(但它不支持令牌的刷新),並對運行特定重定向URI的公共客戶端進行優化,而這一些列操作通常會使用腳本語言在瀏覽器中完成,令牌對訪問者是可見的,且客戶端也不需要驗證。具體流程如下:
步驟解析:
-
客戶端攜帶客戶端標識以及重定向URI到授權服務器;
-
用戶確認是否要授權給客戶端;
-
授權服務器得到許可后,跳轉到指定的重定向地址,並將令牌也包含在了里面;
-
客戶端不攜帶上次獲取到的包含令牌的片段,去請求資源服務器;
-
資源服務器會向瀏覽器返回一個腳本;
-
瀏覽器會根據上一步返回的腳本,去提取在C步驟中獲取到的令牌;
-
瀏覽器將令牌推送給客戶端。
(A步驟)中需要用到的參數,注意在這里要使用"application/x-www-form-urlencoded"格式:
-
response_type 必選項,此值必須為"token"
-
client_id 必選項
-
redirect_uri 可選項
-
scope 可選項
-
state 建議選項
例如:
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
(C步驟)中返回的參數包含:
-
access_token 必選項
-
token_type 必選項
-
expires_in 建議選項
-
scope 可選項
-
state 必選項
例如:
HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
&state=xyz&token_type=example&expires_in=3600
3、resource owner password credentials(密碼模式)
密碼模式適合建立在客戶端與資源所有者具有信任關系的情況下,例如它是一個設備的操作系統或者具有很高權限的應用。這種模式用戶要向客戶端提供自己的用戶名密碼,從而達到向服務提供商索取授權。授權服務器在啟動此類型時,要特別小心,只有在其他的授權方式不被允許的情況下才可以使用這種授權模式。流程如下:
-
客戶端要求使用資源所有者的密碼;
-
資源所有者給予用戶名密碼后,客戶端向授權服務器發起申請令牌的請求;
-
授權服務器將令牌發放給客戶端。
步驟解析:
(B步驟)所需參數:
-
grant_type 必選項 此值必須為"password"
-
username 必選項 用戶名
-
password 必選項 密碼
-
scope 可選項
例如:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
(C步驟)發放令牌:
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"
}
4、client credentials(客戶端模式)
客戶端模式是4種模式中最簡單的一種模式。客戶端可以使用客戶端憑據請求訪問令牌(或者其他支持的認證方式),在這種模式中,客戶端占據主導地位,它不需要用戶的同意,可以直接向授權服務器索取令牌,嚴格來說,該模式並不存在授權的問題,流程如下:
-
客戶端向授權服務器發起請求索要令牌;
-
授權服務器將令牌發放給客戶端。
步驟解析:
(A步驟)中所需的參數::
-
grant_type 必選項 此值必須為client_crendentials
-
scope 可選項
例如:
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
(B步驟)授權服務器返回結果:
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,
"example_parameter":"example_value"
}
六、小結
以以上內容簡要介紹了關於OAuth授權的一些基礎知識以及各種授權模式的具體流程。在后面的文章中,會結合本篇內容,陸續講解如何在.net core中借助IdentityServer4 使用 OAuth 2.0授權。
掃描二維碼關注我的公眾號,共同學習,共同進步!