Identity Server 4 - Hybrid Flow - Claims

solenovex發表於2018-07-05

前一篇 Identity Server 4 - Hybrid Flow - MVC客戶端身份驗證: https://www.cnblogs.com/cgzl/p/9253667.html

Claims

我不知道怎麼樣翻譯這個詞比較好, 所以我一般就不翻譯了.

在前一篇文章裡, MVC客戶端配置身份認證的時候有這麼一句話(Startup的ConfigureServices):

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

官方文件是這樣介紹的: “我們關閉了JWT的Claim 型別對映, 以便允許well-known claims.”

如果我把這句話刪掉, 然後再看看User.Claims的型別和值:

現在有些claim的型別與ID Token裡面的型別名稱是不一樣, 也有一些claim不見了:

 

而加上這句話之後, 現在User claim型別的名字就和ID Token裡面一樣了:

 

再看一下ID Token:

有一些claims並沒有出現在User.Claims裡面. 這是因為這個中介軟體預設情況下會過濾掉一些它認為我們不需要的claim, 例如nbf, amr等.

就先看下面這兩種情況吧:

1. 避免claims被預設過濾掉

如果我想讓中介軟體不要過濾掉nbf和, 也就是把nbf和amr從被過濾掉集合裡移除, 就可以使用這個方法:

然後再看About頁面列印的UserClaims:

這樣nbf和amr就不會被過濾掉了(從過濾掉的集合移除了).

 

2. 刪除某些Claims

假如說我這個MVC客戶端不需要sid和idp, 那麼我可以使用下面的方法:

 

這是一個擴充套件方法, 一定要注意它和Remove方法的區別.........

 

再次操作後, 可以看到這些Claims不見了:

 

ClaimActions還有其他幾個方法, 請自行探索.

 

使用者資訊端點 UserInfo Endpoint 

儘管ID Token裡面可以包含很多使用者的claims, 但是儘量讓ID Token小一點比較好. 所以當MVC客戶端需要更多使用者資訊的時候可以手動請求使用者資訊端點, 這樣做也可以獲得使用者最新的其他資訊.

UserInfo Endpoint的官方文件在這: http://openid.net/specs/openid-connect-core-1_0.html#UserInfo

它要求使用GET或者POST進行請求, 但建議使用GET. 此外請求還需要使用Access Token.

這是一個例子:

成功請求的響應結果是一個JSON物件.

 

首先在IDP裡面再新增一個email scope:

然後在配置的Client裡面新增這個scope:

 

最後為TestUser新增email的claim:

 

回到MVC客戶端的Startup, 這裡也需要新增email這個scope,

而且還要保證這個email不會出現在claims Identity裡面, 這樣我在請求使用者資訊端點的時候才會得到email而不是從User.Claims裡面得到:

 

再次操作後, 可以看到User.Claims裡沒有出現email:

 

下面我需要手動傳送請求到使用者資訊端點來獲取其他資訊:

identity sever 4的這部分文件在: https://identityserver4.readthedocs.io/en/release/endpoints/userinfo.html#identitymodelhttps://github.com/IdentityModel/IdentityModel2

文件提到, 需要為MVC客戶端安裝IdentityModel這個庫:

dotnet add package IdentityModel

隨後, 我把獲取使用者email的程式碼還是放在About Action裡:

首先通過IDP的URI獲得discovery document, 然後從中取出UserInfo端點, 從Cookie裡得到access token, 並用access token從使用者資訊端點獲得claims, 從這些claims裡面取得email並傳遞到About.cshtml.

相應的修改一下About.html:

 

重新操作後看About頁面:

 

對MVC客戶端使用基於角色對授權

首先需要在IDP那裡對兩個使用者新增role這個claim:

分別是管理員角色和註冊使用者角色.

 

OpenID Connect並沒有定義關於角色role相關的scope, 所以我還需要自定義一個scope:

第一個引數是scope的名字, 第二個引數是scope的顯示名, 第三個引數是它所包含的claim型別, 這裡就是“role”.

 

然後還需要客戶端允許請求“roles”這個scope:

 

IDP這邊配置完了, 下面是MVC客戶端的配置, 開啟MVC的startup, 新增“roles”這個scope:

 

下面測試, 可以看到在同意頁面確實請求了角色“roles”這個scope:

 

然後同意後卻無法從User.Claims裡看到角色role 這個claim:

這是因為ASP.NET預設對UserInfo返回的JSON資料裡一些常用的頂層claim進行了對映, 以便它們能夠出現在User.Claims裡面.

我也只需要把JSON裡面的role claim, 對映到User.Claims裡即可:

 

再次操作後, 就可以在User.Claims看到角色了:

 

然後我便可以在MVC客戶端的任意地方通過角色來控制使用者的訪問許可權了, 例如:

但是如何把role claim對映成ASP.NET Core MVC可以識別的角色Roles呢?

可以在MVC裡這樣配置:

該引數主要是配置驗證Token的一些東西, 然而它還可以指定客戶端的Name 和 Role Claim的型別.

 

操作後用兩個使用者分別測試一下, Nick 管理員, 可以訪問About:

 

另一個使用者, Dave 註冊使用者, 則不可以訪問About:

 

這說明角色已經被MVC客戶端識別了.

 

但是對於Dave這個使用者來說, 沒有許可權訪問About時, 頁面顯示非常不友好, 所以下面解決這個問題.

首先建立一個AuthroizationController:

 

然後建立相關的view:

 

最後在Startup裡面配置, 如果沒有許可權就跳轉到這個Action上:

 

再次操作後, Dave點選About後就會因為許可權不足而跳轉到該頁面:

 

今天先到這, 我自己幾乎不用MVC, 我主要是做Web API的, 這部分的內容大部分來自官方文件和其他一些資料綜合出來的.


程式碼: https://github.com/solenovex/Identity-Server-4-Tutorial-Code 02部分

 

相關文章