IdentityServer4 之 Resource Owner Password Credentials 其實有點尷尬
阿新 • • 發佈:2021-01-11
### 前言
接著IdentityServer4的授權模式繼續聊,這篇來說說 Resource Owner Password Credentials授權模式,這種模式在實際應用場景中使用的並不多,只怪其太開放啦,直接在**客戶端**上拿著使用者名稱和密碼就去**授權伺服器**獲取**AccessToken**,這樣容易被**客戶端**拿著使用者名稱和密碼搞壞事;接下來就詳細說說。
### 正文
**Resource Owner Password Credentials**授權模式與上一節說到的[客戶端憑據模式](https://mp.weixin.qq.com/s?__biz=MzU1MzYwMjQ5MQ==&mid=2247484451&idx=1&sn=52d10586571e43432e6a00f3f0877303&chksm=fbf118f7cc8691e1c9b7bf6207ccc07d26371a95c9f8faf4978625a89c5ece0c8c2e1a876af1&scene=21#wechat_redirect)不同,這是有使用者參與的,使用者就是資源擁有者;通過允許在客戶端使用使用者名稱和密碼的方式向授權伺服器獲取AccessToken,AccessToken和使用者相關,即不同的使用者獲取到的AccessToken不一樣。
##### 術語解釋:
- **Resource Owner**:資源所有者,即擁有資源的使用者; 絕大對數小夥伴都應該有自己的QQ,如果沒特殊情況,相信每一個小夥伴的QQ空間中都有自己曾經覺得很酷或很有紀念意義的照片,這裡的照片就是資源,而小夥伴就是資源所有者。 QQ伺服器就是資源伺服器。
#### Resource Owner Password Credentials 流程
![image-20210106122921243](https://i.loli.net/2021/01/06/Q4IRVwWxhdceiKO.png)
流程簡要說明:
1. 首先使用者和客戶端需要提前在授權伺服器上備案過的,使用者沒有備案,在資源伺服器肯定就沒有對應的資源,客戶端沒有備案就不能隨意去授權伺服器獲取AccessToken;
2. 使用者在客戶端上輸入使用者名稱和密碼,並帶上備案過的客戶端憑據一起請求授權伺服器獲取AccessToken;
3. 授權伺服器驗證使用者憑據和客戶端憑據,成功之後直接返回代表該使用者的AccessToken;
4. 使用者在操作時,帶上AccessToken訪問資源伺服器;
5. 資源伺服器正常返回結果,如果沒有AccessToken是不能訪問受保護資源的;
結合流程,看看程式碼如何實現,步伐跟上哦;
這裡資源伺服器和授權伺服器就拷貝之前客戶端模式的程式碼(這樣每種模式的程式碼區分開,方便檢視),在原有基礎上修改程式碼即可;
程式碼地址:https://github.com/zyq025/IDS4Demo
##### >>在原有的授權伺服器上增加程式碼
1. 模擬在授權伺服器中備案使用者,方便測試效果,就在記憶體中模擬;
![image-20210106132546239](https://i.loli.net/2021/01/06/zTZxgj7cEefRpHk.png)
2. 備案新的客戶端,指定其授權方式;
![image-20210106133339652](https://i.loli.net/2021/01/06/c3DjWIGZ1qFlB8z.png)
3. 好啦,到這授權伺服器的修改就完成啦,用postman先測試一下;
![image-20210106135112325](https://i.loli.net/2021/01/06/18H5sg3ZDVElBwG.png)
##### >>授權伺服器修改完啦,資源伺服器不用動,那就到客戶端啦
1. 新建一個Winform窗體程式,簡單佈局安排上;並引入IdentityModel包;
![image-20210106142213334](https://i.loli.net/2021/01/06/hwfogG4szn8UaFS.png)
2. 編寫獲取AccessToken邏輯,在**GetAccessToken按鈕**點選事件中增加程式碼,如下:
![image-20210106150232248](https://i.loli.net/2021/01/06/mThRJt8HzUAuIkP.png)
3. 先啟動授權伺服器,看看access_token執行效果,如下:
![image-20210106150619514](https://i.loli.net/2021/01/06/j4zDhCUAMfydc71.png)
4. 獲取到AccessToken之後就可以訪問受保護的API啦,在**呼叫API按鈕**點選事件中進行邏輯編寫,如下:
![image-20210106151317975](https://i.loli.net/2021/01/06/DquxUeBpwaskCv4.png)
5. 授權伺服器、資源伺服器、客戶端啟動執行看效果,如下:
![image-20210106151654463](https://i.loli.net/2021/01/06/ZPIo564OtxCUvQy.png)
以上就是Resource Owner Password Credentials的使用,流程是不是很簡單。接下來聊聊這種模式的其他話題;
#### Resource Owner Password Credentials的尷尬之處
在oauth2.0中如果使用這種模式,規定是不允許客戶端儲存資源所有者的使用者名稱和密碼的,但如果是第三方客戶端想搞事情,就把使用者資訊先存一把,這樣就導致間接洩露使用者資訊的風險很高(如果第三方客戶端被攻擊了),這也是這種模式在實際應用場景使用比較少的原因,如果有其他模式選擇,不建議使用此模式;
通常以下情況,可以考慮使用:
- 客戶端是可高度信任的,且安全性要有保障;
- 遺留應用,沒有其他好的解決方案,可以使用;
#### 有使用者參與獲取的accessToken和客戶端憑據獲取到的有什麼區別
之前客戶端憑據模式的截圖:
![image-20201231154747613](https://i.loli.net/2021/01/06/6x4CgPKAfQEy1Gh.png)
資源所有者密碼模式的截圖:
![image-20210106162450204](https://i.loli.net/2021/01/06/RscLitSmA9jMy5z.png)
小夥伴肯定看出來不止多一個,但其中比較重要的就是sub這個claim,如果sub存在,呼叫API的access_token就能區分是代表使用者的,否則就是代表客戶端的。即有使用者參與獲取的acess_token是代表使用者的,每個使用者的token都不一樣。
#### refresh_token得補上
refresh_token是為了給access_token進行延長有效期而存在的,為了安全和降低風險,access_token的有效期一般設定的比較短,通常會是兩個小時(根據需要設定),當access_token失效時,常規的做法就是讓其跳轉到登入頁重新登入獲取,這樣頻繁的跳轉到登入頁,使用者體驗及其不好,為避免這種情況,需對access_token進行線上續命,即延長有效期;實現的方案各種各樣,比如有在前端定時檢測的,也有在後端做有效判斷的,但用的相對比較多還是使用refresh_token的形式,當access_token失效時,會採用refresh_token去請求新的access_token,保證使用者正常操作。
如果需要在獲取access_token的時候同時返回refresh_token,需要在授權伺服器上備案客戶端時將**AllowOfflineAccess**設定為true,如下所示:
![image-20210107100506699](https://i.loli.net/2021/01/07/JutC7pl9IkwVQNA.png)
refresh_token具體使用,在後續的案例單獨說吧。
### 總結
關於Resource Owner Password Credentials 就簡單說這麼多,主要是看看如何使用,相信小夥伴在新的專案中應該會很少用到,畢竟拿著使用者名稱和密碼直接在第三方客戶端搞事情,始終還是有風險;下一篇說說**Implicit(簡化模式)**。
一個被程式搞醜的帥小夥,關注"Code綜藝圈",跟我一起學~
![](https://i.loli.net/2021/01/07/l7e8dBOT4acFt