前一篇 Identity Server 4 - Hybrid Flow - MVC客戶端身份驗證: https://www.cnblogs.com/cgzl/p/9253667.html
Claims
我不知道怎么樣翻譯這個詞比較好, 所以我一般就不翻譯了.
在前一篇文章里, MVC客戶端配置身份認證的時候有這么一句話(Startup的ConfigureServices):

官方文檔是這樣介紹的: “我們關閉了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#identitymodel, https://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部分
